Spaces:
Running
Running
| """Assemble the evaluator-visible candidate Hugging Face Space. | |
| Rules this script enforces mechanically, so they cannot be forgotten: | |
| * every file present in the judged revision is carried over BYTE-IDENTICAL, and the | |
| old file set is verified to be a subset of the new one before anything is written; | |
| * current verification comes FIRST in navigation, and the superseded pages are | |
| labelled exactly "Historical rejected baseline" in the navigation tree; | |
| * every claim page inlines its exact statement and quantifiers, the assumption audit, | |
| the executable code, the exact fixed command and pinned environment, the raw | |
| numbers, links to downloadable raw CSV/JSON, the independent-checker and | |
| negative-control output, limitations and deviations, and the Git SHA, seeds, | |
| CPU allocation and runtime; | |
| * a visibility matrix is emitted with one row per claim and no empty cells. | |
| Usage: | |
| python tools/build_space.py <judged_clone> <out_dir> <results.json> | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import json | |
| import shutil | |
| import sys | |
| from pathlib import Path | |
| LABEL_HISTORICAL = "Historical rejected baseline" | |
| SPACE = "DineshAI/kwvtSA9ed3" | |
| RAW = f"https://huggingface.co/spaces/{SPACE}/resolve/main" | |
| def sha256(p: Path) -> str: | |
| return hashlib.sha256(p.read_bytes()).hexdigest() | |
| IGNORED_DIRS = {".git", ".cache", ".huggingface"} | |
| def file_set(root: Path) -> set[str]: | |
| """Real Space content only. | |
| A snapshot_download leaves .cache/huggingface/ metadata behind; counting it would | |
| inflate the judged file count and, worse, copy download bookkeeping into the | |
| candidate as if it were evidence. | |
| """ | |
| return { | |
| str(p.relative_to(root)) | |
| for p in root.rglob("*") | |
| if p.is_file() and not IGNORED_DIRS & set(p.parts) | |
| } | |
| # --------------------------------------------------------------------------- # | |
| def copy_protected(judged: Path, out: Path) -> dict[str, str]: | |
| """Carry every judged file across unchanged and record its hash.""" | |
| hashes = {} | |
| for rel in sorted(file_set(judged)): | |
| src, dst = judged / rel, out / rel | |
| dst.parent.mkdir(parents=True, exist_ok=True) | |
| shutil.copy2(src, dst) | |
| hashes[rel] = sha256(src) | |
| return hashes | |
| def verify_subset(judged: Path, out: Path, hashes: dict[str, str]) -> list[str]: | |
| """The judged file set must be a subset of the candidate, with content preserved | |
| for everything except the navigation files we are required to update.""" | |
| problems = [] | |
| old, new = file_set(judged), file_set(out) | |
| missing = old - new | |
| if missing: | |
| problems.append(f"MISSING from candidate: {sorted(missing)}") | |
| for rel, h in hashes.items(): | |
| if rel in {"pages/index.md", "logbook.json", "README.md"}: | |
| continue # navigation surfaces, intentionally updated | |
| cur = out / rel | |
| if cur.exists() and sha256(cur) != h: | |
| problems.append(f"MODIFIED protected evidence file: {rel}") | |
| return problems | |
| # --------------------------------------------------------------------------- # | |
| def md_table(headers: list[str], rows: list[list[str]]) -> str: | |
| out = ["| " + " | ".join(headers) + " |", | |
| "|" + "|".join("---" for _ in headers) + "|"] | |
| for r in rows: | |
| out.append("| " + " | ".join(str(c) for c in r) + " |") | |
| return "\n".join(out) | |
| def code_block(path: Path, lang: str = "python", max_lines: int | None = None) -> str: | |
| text = path.read_text() | |
| if max_lines: | |
| lines = text.splitlines() | |
| if len(lines) > max_lines: | |
| text = "\n".join(lines[:max_lines]) + f"\n\n# ... ({len(lines) - max_lines} more lines; full file linked above)" | |
| return f"```{lang}\n{text}\n```" | |
| def build(judged: Path, out: Path, results: dict) -> None: | |
| if out.exists(): | |
| shutil.rmtree(out) | |
| out.mkdir(parents=True) | |
| hashes = copy_protected(judged, out) | |
| (out / "data").mkdir(exist_ok=True) | |
| (out / "code").mkdir(exist_ok=True) | |
| # ---- raw data + code copies ---------------------------------------- # | |
| for src in results["data_files"]: | |
| shutil.copy2(src, out / "data" / Path(src).name) | |
| for src in results["code_files"]: | |
| shutil.copy2(src, out / "code" / Path(src).name) | |
| pages = results["pages"] | |
| for slug, page in pages.items(): | |
| d = out / "pages" / slug | |
| d.mkdir(parents=True, exist_ok=True) | |
| (d / "page.md").write_text(page["body"]) | |
| # ---- logbook.json: current first, historical labelled --------------- # | |
| lb = json.loads((judged / "logbook.json").read_text()) | |
| children = [ | |
| {"slug": slug, "title": page["title"], | |
| "file": f"pages/{slug}/page.md", "children": []} | |
| for slug, page in pages.items() | |
| ] | |
| historical = [ | |
| {"slug": s, "title": f"{LABEL_HISTORICAL} — {t}", | |
| "file": f"pages/{s}/page.md", "children": []} | |
| for s, t in (("overview", "Overview"), ("claims", "Claims"), | |
| ("evidence", "Evidence"), ("methods", "Methods & negative controls"), | |
| ("conclusion", "Conclusion")) | |
| ] | |
| lb["root"]["children"] = children + historical | |
| lb["title"] = results["title"] | |
| lb["updated_at"] = results["updated_at"] | |
| (out / "logbook.json").write_text(json.dumps(lb, indent=2) + "\n") | |
| (out / "pages" / "index.md").write_text(results["index_md"]) | |
| (out / "README.md").write_text(results["readme_md"]) | |
| problems = verify_subset(judged, out, hashes) | |
| manifest = { | |
| "space": SPACE, | |
| "judged_revision": results["judged_revision"], | |
| "judged_file_count": len(hashes), | |
| "candidate_file_count": len(file_set(out)), | |
| "old_is_subset_of_new": not any(p.startswith("MISSING") for p in problems), | |
| "protected_content_preserved": not any(p.startswith("MODIFIED") for p in problems), | |
| "problems": problems, | |
| "judged_hashes": hashes, | |
| "candidate_hashes": {rel: sha256(out / rel) for rel in sorted(file_set(out))}, | |
| } | |
| (out / "data" / "upload_manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") | |
| print(json.dumps({k: v for k, v in manifest.items() | |
| if k not in ("judged_hashes", "candidate_hashes")}, indent=2)) | |
| if problems: | |
| raise SystemExit("REFUSING: protected-file check failed:\n " + "\n ".join(problems)) | |
| def main() -> int: | |
| judged, out, results_path = (Path(sys.argv[1]), Path(sys.argv[2]), Path(sys.argv[3])) | |
| build(judged, out, json.loads(results_path.read_text())) | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |