#!/usr/bin/env python3 """Check CC BY 4.0 license metadata for the GRL submission package.""" from __future__ import annotations import json import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] PUBLISH_ROOT = ROOT.parent / "grl_publish" OUT = ROOT / "submission_final" def read(path: Path) -> str: return path.read_text(encoding="utf-8", errors="replace") if path.exists() else "" def has(path: Path, needle: str) -> bool: return needle.lower() in read(path).lower() def yaml_license_ok(readme: Path) -> bool: text = read(readme) if not text.startswith("---"): return False parts = text.split("---", 2) if len(parts) < 3: return False return re.search(r"(?mi)^license:\s*cc-by-4\.0\s*$", parts[1]) is not None def main() -> int: OUT.mkdir(parents=True, exist_ok=True) failures: list[str] = [] warnings: list[str] = [] main_tex = ROOT / "main.tex" readme_reproduce = ROOT / "README_reproduce.md" citation = ROOT / "CITATION.cff" license_file = ROOT / "LICENSE" notice_file = ROOT / "NOTICE" publish_readme = PUBLISH_ROOT / "README.md" publish_license = PUBLISH_ROOT / "LICENSE" publish_notice = PUBLISH_ROOT / "NOTICE" publish_citation = PUBLISH_ROOT / "CITATION.cff" for path in [license_file, publish_license]: if not path.exists(): failures.append(f"Missing LICENSE: {path}") elif not has(path, "CC-BY-4.0") or not has(path, "https://creativecommons.org/licenses/by/4.0/"): failures.append(f"LICENSE does not contain CC-BY-4.0 and license URL: {path}") for path in [notice_file, publish_notice]: if not path.exists(): failures.append(f"Missing NOTICE: {path}") elif not has(path, "snr_bias") or not has(path, "CC BY 4.0"): failures.append(f"NOTICE missing snr_bias archive URL/name or CC BY 4.0: {path}") if not has(readme_reproduce, "CC BY 4.0"): failures.append("README_reproduce.md does not contain CC BY 4.0.") if not has(publish_readme, "CC BY 4.0"): failures.append("grl_publish/README.md does not contain CC BY 4.0.") if not yaml_license_ok(publish_readme): failures.append("grl_publish/README.md Hugging Face YAML metadata missing license: cc-by-4.0.") for path in [citation, publish_citation]: if not path.exists(): failures.append(f"Missing CITATION.cff: {path}") elif not has(path, "CC-BY-4.0") or not has(path, "snr_bias"): failures.append(f"CITATION.cff missing CC-BY-4.0 or snr_bias archive URL/name: {path}") manuscript = read(main_tex) forbidden = [ "no separate license file", "license file was present", "TBD", "placeholder", "Requires author confirmation", "email to be added", "Affiliation to be added", ] for token in forbidden: if token.lower() in manuscript.lower(): failures.append(f"Forbidden manuscript text remains: {token}") required_open_research = [ "CC BY 4.0", "snr_bias", "Hugging Face", "SeismicX-Cont", "DOI: 10.57967/hf/9006", "SeisDispFusion-NCF", "DOI: 10.57967/hf/9114", r"\citeA{yu2026snrbias}", r"\citeA{yu2026seismicxcont}", r"\citeA{yu2026seisdispfusionncf}", ] for token in required_open_research: if token not in manuscript: failures.append(f"Open Research missing required text: {token}") bad_creditx1 = [ "CREDIT-X1local data are redistributed", "CREDIT-X1local waveforms are redistributed", "raw CREDIT-X1local data are included", ] for token in bad_creditx1: if token.lower() in manuscript.lower(): failures.append(f"Potential false redistribution claim: {token}") if not PUBLISH_ROOT.exists(): warnings.append(f"Publish archive root not found: {PUBLISH_ROOT}") status = "PASS" if not failures else "FAIL" report = { "overall_status": status, "failures": failures, "warnings": warnings, "checked_paths": { "manuscript_root": str(ROOT), "publish_root": str(PUBLISH_ROOT), "main_tex": str(main_tex), "publish_readme": str(publish_readme), }, } (OUT / "license_check.json").write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8") lines = [ "# License Check", "", f"- Overall status: `{status}`", "", "## Failures", "", *([f"- {item}" for item in failures] or ["- None"]), "", "## Warnings", "", *([f"- {item}" for item in warnings] or ["- None"]), ] (OUT / "license_check.md").write_text("\n".join(lines) + "\n", encoding="utf-8") print(json.dumps(report, indent=2)) return 0 if status == "PASS" else 1 if __name__ == "__main__": raise SystemExit(main())