Add librarian Stage 1 oversize check

Third Stage 1 piece: scripts/librarian_check_oversize.py walks
non-archive markdown files and flags any over the 500-line soft cap
declared in AGENTS.md. Wired into scripts/librarian.sh.

Caught one real finding on first run: docs/performance.md at 914
lines. Splitting it into sub-topic notes is a separate cleanup task
— surfaced for the user, not auto-applied.

Updates docs/plans/librarian.md Progress + sets the next concrete
step to a stale-plan checker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 23:31:37 +09:00
co-authored by Claude Opus 4.7
parent 0b363b5031
commit 5a1b944931
3 changed files with 109 additions and 5 deletions
+6
View File
@@ -21,6 +21,12 @@ if ! uv run python scripts/librarian_check_citations.py; then
fi
echo
echo "→ File size (500-line soft cap from AGENTS.md)"
if ! uv run python scripts/librarian_check_oversize.py; then
overall=1
fi
echo
if [ "$overall" -eq 0 ]; then
echo "All Stage 1 checks passed."
else
+92
View File
@@ -0,0 +1,92 @@
"""Oversize file check for librarian Stage 1.
Walks markdown files and flags any whose line count exceeds the
soft cap declared in AGENTS.md ("Docs & Experiment Workflow"
section). Skips read-only archive doc directories — splitting them
isn't an option.
Usage:
uv run python scripts/librarian_check_oversize.py
"""
from __future__ import annotations
import sys
from pathlib import Path
SOFT_CAP_LINES = 500
EXCLUDED_DIRS = {
".git",
".mypy_cache",
".pytest_cache",
".ruff_cache",
".venv",
"__pycache__",
"build",
"dist",
"node_modules",
"runs",
"target",
"tools",
"wheels",
}
EXCLUDED_DOC_PREFIXES = (
Path("docs/archive"),
Path("docs/plans/archive"),
)
def _repo_root() -> Path:
current = Path(__file__).resolve()
for parent in current.parents:
if (parent / "pyproject.toml").is_file():
return parent
raise RuntimeError("pyproject.toml을 찾을 수 없어 repository root를 판정할 수 없습니다.")
def _is_excluded(rel: Path) -> bool:
if any(part in EXCLUDED_DIRS for part in rel.parts):
return True
return any(prefix in rel.parents for prefix in EXCLUDED_DOC_PREFIXES)
def _markdown_files(root: Path) -> list[Path]:
files: list[Path] = []
for path in root.rglob("*.md"):
rel = path.relative_to(root)
if not _is_excluded(rel):
files.append(path)
return sorted(set(files))
def _line_count(path: Path) -> int:
with path.open(encoding="utf-8", errors="replace") as f:
return sum(1 for _ in f)
def main() -> int:
root = _repo_root()
files = _markdown_files(root)
if not files:
print("검사할 Markdown 파일이 없습니다.", file=sys.stderr)
return 1
over = [(path, _line_count(path)) for path in files]
over = [(p, n) for p, n in over if n > SOFT_CAP_LINES]
if not over:
print(f"All markdown files under {SOFT_CAP_LINES}-line soft cap.")
return 0
over.sort(key=lambda item: -item[1])
print(f"Files over {SOFT_CAP_LINES}-line soft cap:")
for path, n in over:
rel = path.relative_to(root)
print(f" {n:5d} {rel}")
return 1
if __name__ == "__main__":
raise SystemExit(main())