Files
agent/evaluation-site/build_research_data.py
T
2026-07-28 00:57:15 +08:00

137 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""Build the browser evidence index from the committed Markdown ledger."""
from __future__ import annotations
import argparse
import hashlib
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
LEDGER = ROOT / "research" / "completion-verification" / "evidence-ledger.md"
OUTPUT = ROOT / "evaluation-site" / "assets" / "evidence-data.js"
SECTION_SLUGS = {
"完成证明与 evaluator 误差": "verification",
"测试、benchmark 和协议会不会错误认证": "protocol",
"故障发现、定位和恢复": "recovery",
"变更风险、协作和重复可靠性": "reliability",
"全文池与排除": "context",
}
def parse_link(value: str) -> tuple[str, str]:
match = re.fullmatch(r"\[([^\]]+)\]\((https?://[^)]+)\)", value.strip())
if not match:
raise ValueError(f"Invalid paper link: {value}")
return match.group(1), match.group(2)
def parse_ledger(text: str) -> list[dict[str, str]]:
section = ""
records: list[dict[str, str]] = []
for raw_line in text.splitlines():
heading = re.match(r"^## \d+\.\s+(.+)$", raw_line)
if heading:
title = heading.group(1).strip()
section = SECTION_SLUGS.get(title, "")
continue
if not raw_line.startswith("| ["):
continue
columns = [column.strip() for column in raw_line.strip().strip("|").split("|")]
if len(columns) not in {3, 5}:
raise ValueError(f"Unexpected table row with {len(columns)} columns: {raw_line}")
title, url = parse_link(columns[0])
arxiv_match = re.search(r"(\d{4}\.\d{5})", url)
if not arxiv_match:
raise ValueError(f"Missing arXiv id: {url}")
arxiv_id = arxiv_match.group(1)
title = re.sub(rf",\s*{re.escape(arxiv_id)}$", "", title)
record = {
"id": arxiv_id,
"title": title,
"url": url,
"depth": columns[1],
"theme": section,
}
if len(columns) == 5:
record.update(
{
"evidence": columns[2],
"supports": columns[3],
"boundary": columns[4],
}
)
else:
record.update(
{
"evidence": "",
"supports": "",
"boundary": columns[2],
}
)
records.append(record)
return records
def build_payload(text: str) -> dict[str, object]:
records = parse_ledger(text)
counts = {
"pool": len(records),
"audited": sum(record["depth"] in {"core", "support"} for record in records),
"core": sum(record["depth"] == "core" for record in records),
"support": sum(record["depth"] == "support" for record in records),
"context": sum(record["depth"] == "context" for record in records),
}
return {
"source": "research/completion-verification/evidence-ledger.md",
"source_sha256": hashlib.sha256(text.encode("utf-8")).hexdigest(),
"counts": counts,
"records": records,
}
def render(payload: dict[str, object]) -> str:
body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
return (
"/* Generated by evaluation-site/build_research_data.py. */\n"
f"window.K1412_EVIDENCE={body};\n"
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--check",
action="store_true",
help="Fail if the generated browser data is stale.",
)
args = parser.parse_args()
expected = render(build_payload(LEDGER.read_text(encoding="utf-8")))
if args.check:
if not OUTPUT.exists() or OUTPUT.read_text(encoding="utf-8") != expected:
print(f"stale: {OUTPUT.relative_to(ROOT)}")
return 1
print(f"ok: {OUTPUT.relative_to(ROOT)}")
return 0
OUTPUT.write_text(expected, encoding="utf-8")
print(f"wrote: {OUTPUT.relative_to(ROOT)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())