Accept first survey batch + add commit-hash post-processing
Spot-check of the three drafts gemini produced in the --max 3 survey smoke test: all cited file paths exist, line numbers and function names land within 1-2 lines of actual symbols (game.pyx:217 cdef class GameState, evaluate.py:220 batched-entropy block, trainer.py:892 _evaluate_parallel, action_distribution at evaluate.py:238 with cited code at line 250 inside it). Numbers cross-checked against archives match. Conclusions preserved. The one systemic weakness was the Last-verified commit field: gemini left a `<short-hash>` placeholder, a literal `HEAD`, or omitted the commit entirely depending on the call. Fixed in two places: 1. Manually patched the three drafts before acceptance and copied them into docs/research/. 2. Added _current_commit_sha and _post_process_draft helpers to both librarian_survey.py and librarian_promote.py. The drafts now go through `**Last verified:**` line normalization that substitutes today's date and `git rev-parse --short HEAD` before being written to disk. Future runs converge deterministically. Net: docs/research/ gains classic-port-notes.md, deep-cfr-batched-evaluation.md, and deep-cfr-evaluation-profile.md. 12 archive entries remain unprocessed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,6 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
@@ -37,6 +36,7 @@ LLM_COMMANDS = {
|
||||
}
|
||||
|
||||
DATE_SUFFIX = re.compile(r"-\d{4}-\d{2}-\d{2}$")
|
||||
LAST_VERIFIED = re.compile(r"^\*\*Last verified:\*\*[^\n]*$", re.MULTILINE)
|
||||
|
||||
|
||||
def _repo_root() -> Path:
|
||||
@@ -47,6 +47,34 @@ def _repo_root() -> Path:
|
||||
raise RuntimeError("pyproject.toml을 찾을 수 없어 repository root를 판정할 수 없습니다.")
|
||||
|
||||
|
||||
def _current_commit_sha(root: Path) -> str:
|
||||
"""Resolve HEAD to a short SHA. Returns 'unknown' if git is unavailable."""
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--short", "HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
cwd=root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return "unknown"
|
||||
return result.stdout.strip() or "unknown"
|
||||
|
||||
|
||||
def _post_process_draft(content: str, commit_sha: str) -> str:
|
||||
"""Normalize a draft before writing to disk.
|
||||
|
||||
The LLM is unreliable about running `git` itself in headless mode; it
|
||||
tends to leave `<short-hash>` placeholders or literal `HEAD` strings.
|
||||
Rewrite the `**Last verified:**` line in place with today's date and
|
||||
the real short SHA. If the line is missing entirely, leave the draft
|
||||
untouched so the omission stays visible during review.
|
||||
"""
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
new_line = f"**Last verified:** {today}, commit `{commit_sha}`"
|
||||
return LAST_VERIFIED.sub(new_line, content, count=1)
|
||||
|
||||
|
||||
def _assemble_prompt(
|
||||
system_prompt: str,
|
||||
rel_archive: Path,
|
||||
@@ -167,7 +195,9 @@ def main() -> int:
|
||||
print(result.stderr, file=sys.stderr)
|
||||
return result.returncode
|
||||
|
||||
draft_path.write_text(result.stdout, encoding="utf-8")
|
||||
commit_sha = _current_commit_sha(root)
|
||||
draft_text = _post_process_draft(result.stdout, commit_sha)
|
||||
draft_path.write_text(draft_text, encoding="utf-8")
|
||||
print(f"Draft written to: {draft_path.relative_to(root)}")
|
||||
|
||||
if args.accept:
|
||||
@@ -177,7 +207,7 @@ def main() -> int:
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
shutil.copyfile(draft_path, target)
|
||||
target.write_text(draft_text, encoding="utf-8")
|
||||
print(f"Copied to: {rel_target}")
|
||||
print("Next: review the diff and `git add` + commit if you're satisfied.")
|
||||
else:
|
||||
|
||||
@@ -40,6 +40,7 @@ LLM_COMMANDS = {
|
||||
}
|
||||
|
||||
DATE_SUFFIX = re.compile(r"-\d{4}-\d{2}-\d{2}$")
|
||||
LAST_VERIFIED = re.compile(r"^\*\*Last verified:\*\*[^\n]*$", re.MULTILINE)
|
||||
|
||||
|
||||
def _repo_root() -> Path:
|
||||
@@ -78,6 +79,34 @@ def _assemble_prompt(
|
||||
)
|
||||
|
||||
|
||||
def _current_commit_sha(root: Path) -> str:
|
||||
"""Resolve HEAD to a short SHA. Returns 'unknown' if git is unavailable."""
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--short", "HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
cwd=root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return "unknown"
|
||||
return result.stdout.strip() or "unknown"
|
||||
|
||||
|
||||
def _post_process_draft(content: str, commit_sha: str) -> str:
|
||||
"""Normalize a draft before writing to disk.
|
||||
|
||||
The LLM is unreliable about running `git` itself in headless mode; it
|
||||
tends to leave `<short-hash>` placeholders or literal `HEAD` strings.
|
||||
Rewrite the `**Last verified:**` line in place with today's date and
|
||||
the real short SHA. If the line is missing entirely, leave the draft
|
||||
untouched so the omission stays visible during review.
|
||||
"""
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
new_line = f"**Last verified:** {today}, commit `{commit_sha}`"
|
||||
return LAST_VERIFIED.sub(new_line, content, count=1)
|
||||
|
||||
|
||||
def _has_counterpart(archive_stem_no_date: str, research_stems: set[str]) -> bool:
|
||||
"""True if a research note already covers this archive entry.
|
||||
|
||||
@@ -150,6 +179,7 @@ def main() -> int:
|
||||
return 1
|
||||
|
||||
system_prompt = (root / "scripts" / "librarian-prompt.md").read_text(encoding="utf-8")
|
||||
commit_sha = _current_commit_sha(root)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
|
||||
out_dir = root / "runs" / "tmp" / f"librarian-survey-{timestamp}"
|
||||
@@ -186,9 +216,10 @@ def main() -> int:
|
||||
skips += 1
|
||||
print(f" SKIP ({output[:80]})", file=sys.stderr)
|
||||
else:
|
||||
(out_dir / f"{stem_out}.md").write_text(output, encoding="utf-8")
|
||||
normalized = _post_process_draft(output, commit_sha)
|
||||
(out_dir / f"{stem_out}.md").write_text(normalized, encoding="utf-8")
|
||||
drafts += 1
|
||||
print(f" draft ({len(output)} chars)", file=sys.stderr)
|
||||
print(f" draft ({len(normalized)} chars)", file=sys.stderr)
|
||||
|
||||
print()
|
||||
print(f"Survey complete: {drafts} drafts, {skips} skips, {errors} errors.")
|
||||
|
||||
Reference in New Issue
Block a user