spb/localvm-research Public License
Running LLMs larger than memory on a consumer Mac — falsification-driven research: margin-gated deferred refinement, out-of-core verification on Apple Silicon. TR-01 published.
Python 63.2%
JavaScript 23.5%
CSS 11.8%
Shell 0.9%
Makefile 0.5%
1#!/usr/bin/env python32# =============================================================================3# Project : localvm-research4# File : tools/check_headers.py5# Purpose : CI-style enforcement of the mandatory author header (CLAUDE.md §0.1)6# Author : Simon-Pierre Boucher7# Contact : contact@spboucher.ai8# Created : 2026-08-119# Modified : 2026-08-1110# Platform : macOS / Apple Silicon (arm64)11# License : All rights reserved (research code)12# =============================================================================13"""Fail (exit 1) if any tracked source file lacks a conforming author header.1415Usage:16 python3 tools/check_headers.py # check all git-tracked files17 python3 tools/check_headers.py FILE... # check specific files1819Rules enforced (see CLAUDE.md §0.1):20 * Comment-style sources (.py .sh .zsh .yaml .yml .toml .cff Makefile21 CMakeLists.txt) must contain the '#'-style header block near the top.22 * C-family sources (.c .cpp .h .hpp .metal .swift .m .mm) must contain the23 '//'-style header block near the top.24 * Markdown documents must begin with YAML front matter declaring25 project/author/contact.26 * A shebang line may precede the header.2728Exemptions: generated results under results/, LICENSE, .gitignore is checked29(it supports comments), CLAUDE.md (the charter predates the convention and is30the specification itself).31"""3233from __future__ import annotations3435import subprocess36import sys37from pathlib import Path3839REPO_ROOT = Path(__file__).resolve().parent.parent4041REQUIRED_FIELDS = ("Project", "File", "Purpose", "Author", "Contact",42 "Created", "Modified", "Platform", "License")43AUTHOR = "Simon-Pierre Boucher"44CONTACT = "contact@spboucher.ai"4546HASH_EXTS = {".py", ".sh", ".zsh", ".bash", ".yaml", ".yml", ".toml", ".cff"}47SLASH_EXTS = {".c", ".cc", ".cpp", ".h", ".hpp", ".metal", ".swift", ".m", ".mm"}48HASH_NAMES = {"Makefile", "CMakeLists.txt", ".gitignore"}4950EXEMPT_NAMES = {"LICENSE", "CLAUDE.md", "MEMORY.md"}51EXEMPT_DIRS = {"results"}52# How many leading lines to scan for the header block (allows shebang etc.).53SCAN_LINES = 20545556def tracked_files() -> list[Path]:57 out = subprocess.run(58 ["git", "ls-files"], cwd=REPO_ROOT, capture_output=True, text=True, check=True59 ).stdout60 return [REPO_ROOT / line for line in out.splitlines() if line.strip()]616263def is_exempt(path: Path) -> bool:64 rel = path.relative_to(REPO_ROOT)65 if rel.name in EXEMPT_NAMES:66 return True67 return bool(rel.parts and rel.parts[0] in EXEMPT_DIRS)686970def check_comment_header(lines: list[str], prefix: str) -> list[str]:71 """Check for a comment-style header with all required fields near the top."""72 head = "\n".join(lines[:SCAN_LINES])73 errors = []74 for field in REQUIRED_FIELDS:75 if f"{prefix} {field}" not in head and f"{prefix} {field}" not in head:76 errors.append(f"missing header field: {field}")77 if AUTHOR not in head:78 errors.append(f"missing author name '{AUTHOR}'")79 if CONTACT not in head:80 errors.append(f"missing contact '{CONTACT}'")81 return errors828384def check_markdown_front_matter(lines: list[str]) -> list[str]:85 if not lines or lines[0].strip() != "---":86 return ["markdown file must start with YAML front matter (---)"]87 errors = []88 try:89 end = next(i for i in range(1, min(len(lines), SCAN_LINES)) if lines[i].strip() == "---")90 except StopIteration:91 return ["unterminated YAML front matter"]92 block = "\n".join(lines[1:end])93 for key in ("project: localvm-research", f"author: {AUTHOR}", f"contact: {CONTACT}"):94 if key not in block:95 errors.append(f"front matter missing '{key}'")96 return errors979899def check_file(path: Path) -> list[str]:100 try:101 text = path.read_text(encoding="utf-8", errors="replace")102 except OSError as exc:103 return [f"unreadable: {exc}"]104 lines = text.splitlines()105 if lines and lines[0].startswith("#!"):106 lines = lines[1:]107108 name, ext = path.name, path.suffix109 if ext in HASH_EXTS or name in HASH_NAMES:110 return check_comment_header(lines, "#")111 if ext in SLASH_EXTS:112 return check_comment_header(lines, "//")113 if ext == ".md":114 return check_markdown_front_matter(lines)115 return [] # other file types are not subject to the header rule116117118def main(argv: list[str]) -> int:119 paths = [Path(p).resolve() for p in argv] if argv else tracked_files()120 failures: dict[str, list[str]] = {}121 checked = 0122 for path in paths:123 if not path.is_file() or is_exempt(path):124 continue125 errors = check_file(path)126 if path.suffix in HASH_EXTS | SLASH_EXTS | {".md"} or path.name in HASH_NAMES:127 checked += 1128 if errors:129 failures[str(path.relative_to(REPO_ROOT))] = errors130131 if failures:132 print(f"HEADER CHECK FAILED — {len(failures)} non-conforming file(s):\n")133 for rel, errors in sorted(failures.items()):134 print(f" {rel}")135 for err in errors:136 print(f" - {err}")137 return 1138 print(f"Header check passed ({checked} files checked).")139 return 0140141142if __name__ == "__main__":143 sys.exit(main(sys.argv[1:]))144