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:
+11
-5
@@ -134,6 +134,13 @@ operator applies the patch.
|
|||||||
- ✅ Stage 1 orchestrator: `scripts/librarian.sh`. Runs every Stage 1
|
- ✅ Stage 1 orchestrator: `scripts/librarian.sh`. Runs every Stage 1
|
||||||
check in order, aggregates exit code, prints findings inline. Single
|
check in order, aggregates exit code, prints findings inline. Single
|
||||||
entry point for users and (future) cron.
|
entry point for users and (future) cron.
|
||||||
|
- ✅ AGENTS.md mentions `scripts/librarian.sh` as the doc-lint entry
|
||||||
|
point in "Notes For Future Agents" (commit `0b363b5`).
|
||||||
|
- ✅ Stage 1, piece 3: `scripts/librarian_check_oversize.py`. Flags
|
||||||
|
any non-archive markdown file over the 500-line soft cap declared
|
||||||
|
in AGENTS.md. Caught one real finding on first run:
|
||||||
|
`docs/performance.md` at 914 lines — split into sub-topics deferred
|
||||||
|
as a separate task.
|
||||||
|
|
||||||
## Stage 1 Remaining Checks
|
## Stage 1 Remaining Checks
|
||||||
|
|
||||||
@@ -142,11 +149,10 @@ operator applies the patch.
|
|||||||
judgment is the open question).
|
judgment is the open question).
|
||||||
- MEMORY.md drift (index lines vs target file `description:` frontmatter).
|
- MEMORY.md drift (index lines vs target file `description:` frontmatter).
|
||||||
- Duplicate prose (high-overlap pairs across archive vs research).
|
- Duplicate prose (high-overlap pairs across archive vs research).
|
||||||
- Oversize files (>500-line soft cap from AGENTS.md).
|
|
||||||
|
|
||||||
## Next Concrete Step
|
## Next Concrete Step
|
||||||
|
|
||||||
Mention `scripts/librarian.sh` in AGENTS.md so agents and humans know
|
Stale plan check (`scripts/librarian_check_stale_plans.py`). Walks
|
||||||
it exists as the canonical Stage 1 entry point. After that, pick one
|
`docs/plans/*.md` and flags files whose mtime is older than N days
|
||||||
of the remaining checks above to add as the next checker (oversize
|
AND whose path hasn't appeared in `git log` over the same window.
|
||||||
files is the cheapest; stale plans is the most useful).
|
This catches plans that drift out of mind without being archived.
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ if ! uv run python scripts/librarian_check_citations.py; then
|
|||||||
fi
|
fi
|
||||||
echo
|
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
|
if [ "$overall" -eq 0 ]; then
|
||||||
echo "All Stage 1 checks passed."
|
echo "All Stage 1 checks passed."
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -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())
|
||||||
Reference in New Issue
Block a user