ropedia-xperience-10m-task-baselines / scripts /validate_mirror_parity.py
cy0307's picture
Publish Ropedia Xperience-10M task baseline cards
31e3087 verified
#!/usr/bin/env python3
"""Validate parity between the repo and prepared Hugging Face mirrors.
This is a publisher-side check. It compares critical website data, figures, and
validator scripts across the local repo, prepared HF Space bundle, prepared HF
artifact dataset bundle, and prepared HF model bundle before upload.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_HF_ROOT = ROOT.parent / "hf_publish"
DEFAULT_OUTPUT = ROOT / "docs/data/mirror_parity.json"
DATA_FILES = [
"audio_ablation_summary.json",
"artifact_index.json",
"brand_assets.json",
"evidence_contract.json",
"evaluation_protocol.json",
"figure_index.json",
"foundation_model_plan.json",
"live_publication_status.json",
"modality_atlas.json",
"project_brief.json",
"project_manifest.json",
"project_packet.json",
"project_status.json",
"publication_audit.json",
"public_surface_qa.json",
"quality_gates.json",
"rendered_site_check.json",
"reproducibility_matrix.json",
"research_roadmap.json",
"research_roadmap_interactive.json",
"research_takeaways.json",
"research_direction_extensions.json",
"research_directions.json",
"scope_claims_audit.json",
"single_episode_explorer.json",
"source_alignment_audit.json",
"summary_metrics.json",
"task_surface_integrity.json",
"task_walkthroughs.json",
"website_integrity.json",
"xperience10m_dataset_card_alignment.json",
]
ASSET_FILES = [
"charts/audio_ablation_delta.svg",
"brand/xperience10m-logo-apple-touch.png",
"brand/xperience10m-logo-favicon-32.png",
"brand/xperience10m-logo-favicon-64.png",
"brand/xperience10m-logo-mark.png",
"brand/xperience10m-logo-mark-192.png",
"brand/xperience10m-logo-mark-512.png",
"brand/xperience10m-logo-social-card.png",
"task_suite_infographic.png",
"pipeline_diagram.png",
"task_architectures.png",
"modalities/audio.png",
"modalities/depth.jpg",
"modalities/inertial.png",
"modalities/language.png",
"modalities/motion_capture.png",
"modalities/pose_slam.png",
"modalities/video.jpg",
]
SCRIPT_FILES = [
"audio_ablation_and_raw_upgrade.py",
"build_artifact_index.py",
"build_brand_assets.py",
"build_evaluation_protocol.py",
"build_figure_index.py",
"build_quality_gates.py",
"build_public_surface_qa.py",
"build_rendered_site_check.py",
"build_interactive_research_roadmap.py",
"build_single_episode_explorer.py",
"build_research_takeaways.py",
"single_episode_diagnostics.py",
"verify_live_publication.py",
"validate_mirror_parity.py",
"validate_publication_package.py",
"validate_scope_claims.py",
"validate_source_alignment.py",
"validate_task_surface.py",
"validate_website_integrity.py",
"publish_hf_bundles.py",
]
WEBSITE_FILES = [
"apple-touch-icon.png",
"favicon.png",
"index.html",
"research_roadmap.html",
"single_episode_explorer.html",
"site.webmanifest",
]
RESULT_FILES = [
"audio_ablation/AUDIO_ABLATION_SUMMARY.md",
"audio_ablation/audio_ablation_metrics.csv",
"audio_ablation/audio_ablation_summary.json",
"audio_ablation/audio_delta_summary.csv",
"audio_ablation/raw_logmel_fisheye_cam0_sr16000_mels64_fft512_hop160.npz",
"single_episode_diagnostics/provenance.json",
"single_episode_diagnostics/README.md",
"single_episode_diagnostics/modality_ablation/ablation_metrics.csv",
"single_episode_diagnostics/modality_ablation/ablation_summary.json",
"single_episode_diagnostics/object_labels/object_vocab.json",
"single_episode_diagnostics/object_labels/window_object_labels.csv",
"single_episode_diagnostics/timeline_overlay/timeline_overlay.csv",
"single_episode_diagnostics/alignment_stress/alignment_shift_metrics.csv",
"single_episode_diagnostics/alignment_stress/alignment_stress_summary.json",
]
DOC_FILES = [
"QUALITY_GATES.md",
"EVALUATION_PROTOCOL.md",
"FIGURE_INDEX.md",
"FOUNDATION_MODEL_PLAN.md",
"PROJECT_BRIEF.md",
"RENDERED_SITE_CHECK.md",
"RESEARCH_ROADMAP.md",
"PROJECT_STATUS.md",
"PUBLIC_SURFACE_QA.md",
"RESEARCH_TAKEAWAYS.md",
"SOURCE_ALIGNMENT_AUDIT.md",
"XPERIENCE10M_DATASET_CARD_ALIGNMENT.md",
]
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def display_path(path: Path, hf_root: Path) -> str:
resolved = path.resolve()
bases = [
("hf_space", hf_root / "space"),
("hf_artifacts", hf_root / "artifacts"),
("hf_model", hf_root / "model"),
("repo", ROOT),
("hf_publish", hf_root),
]
for label, base in bases:
try:
return f"{label}:{resolved.relative_to(base.resolve()).as_posix()}"
except ValueError:
continue
return path.name
def file_record(path: Path, hf_root: Path) -> dict:
record = {
"path": display_path(path, hf_root),
"exists": path.exists(),
}
if path.exists() and path.is_file():
record["bytes"] = path.stat().st_size
record["sha256"] = sha256(path)
else:
record["bytes"] = 0
record["sha256"] = None
return record
def parity_group(name: str, local_path: Path, mirrors: dict[str, Path], hf_root: Path) -> dict:
local = file_record(local_path, hf_root)
mirror_records = {surface: file_record(path, hf_root) for surface, path in mirrors.items()}
failures = []
if not local["exists"]:
failures.append({"surface": "repo", "kind": "missing", "path": local["path"]})
for surface, record in mirror_records.items():
if not record["exists"]:
failures.append({"surface": surface, "kind": "missing", "path": record["path"]})
continue
if local["exists"] and record["sha256"] != local["sha256"]:
failures.append(
{
"surface": surface,
"kind": "hash_mismatch",
"path": record["path"],
"expected_sha256": local["sha256"],
"actual_sha256": record["sha256"],
}
)
return {
"name": name,
"status": "pass" if not failures else "fail",
"local": local,
"mirrors": mirror_records,
"failures": failures,
}
def build_report(hf_root: Path) -> dict:
groups = []
for filename in DATA_FILES:
groups.append(
parity_group(
f"data/{filename}",
ROOT / "docs/data" / filename,
{
"hf_space": hf_root / "space/data" / filename,
"hf_artifacts": hf_root / "artifacts/docs/data" / filename,
"hf_model": hf_root / "model/metrics" / filename,
},
hf_root,
)
)
for filename in ASSET_FILES:
groups.append(
parity_group(
f"assets/{filename}",
ROOT / "docs/assets" / filename,
{
"hf_space": hf_root / "space/assets" / filename,
"hf_artifacts_docs": hf_root / "artifacts/docs/assets" / filename,
"hf_artifacts_card": hf_root / "artifacts/assets" / filename,
"hf_model": hf_root / "model/assets" / filename,
},
hf_root,
)
)
for filename in SCRIPT_FILES:
groups.append(
parity_group(
f"scripts/{filename}",
ROOT / "scripts" / filename,
{
"hf_artifacts": hf_root / "artifacts/scripts" / filename,
"hf_model": hf_root / "model/scripts" / filename,
},
hf_root,
)
)
for filename in WEBSITE_FILES:
groups.append(
parity_group(
f"website/{filename}",
ROOT / "docs" / filename,
{
"hf_space": hf_root / "space" / filename,
"hf_artifacts_docs": hf_root / "artifacts/docs" / filename,
},
hf_root,
)
)
for filename in RESULT_FILES:
groups.append(
parity_group(
f"results/{filename}",
ROOT / "results" / filename,
{
"hf_space": hf_root / "space/results" / filename,
"hf_artifacts": hf_root / "artifacts/results" / filename,
"hf_model": hf_root / "model/results" / filename,
},
hf_root,
)
)
for filename in DOC_FILES:
groups.append(
parity_group(
f"docs/{filename}",
ROOT / filename,
{
"hf_space": hf_root / "space" / filename,
"hf_artifacts": hf_root / "artifacts" / filename,
"hf_model": hf_root / "model" / filename,
},
hf_root,
)
)
failures = [
{"group": group["name"], **failure}
for group in groups
for failure in group["failures"]
]
by_surface: dict[str, int] = {}
for failure in failures:
by_surface[failure["surface"]] = by_surface.get(failure["surface"], 0) + 1
return {
"status": "pass" if not failures else "fail",
"generated_at_utc": datetime.now(timezone.utc).isoformat(timespec="seconds"),
"hf_root": "hf_publish",
"summary": {
"group_count": len(groups),
"failure_count": len(failures),
"failures_by_surface": by_surface,
},
"checks": [
{
"name": "repo_hf_space_artifact_model_data_parity",
"status": "pass"
if not any(failure["group"].startswith("data/") for failure in failures)
else "fail",
},
{
"name": "repo_hf_visual_asset_parity",
"status": "pass"
if not any(failure["group"].startswith("assets/") for failure in failures)
else "fail",
},
{
"name": "repo_hf_validator_script_parity",
"status": "pass"
if not any(failure["group"].startswith("scripts/") for failure in failures)
else "fail",
},
{
"name": "repo_hf_website_html_parity",
"status": "pass"
if not any(failure["group"].startswith("website/") for failure in failures)
else "fail",
},
{
"name": "repo_hf_diagnostic_result_parity",
"status": "pass"
if not any(failure["group"].startswith("results/") for failure in failures)
else "fail",
},
{
"name": "repo_hf_quality_doc_parity",
"status": "pass"
if not any(failure["group"].startswith("docs/") for failure in failures)
else "fail",
},
],
"groups": groups,
"failures": failures,
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--hf-root", type=Path, default=DEFAULT_HF_ROOT)
parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
args = parser.parse_args()
report = build_report(args.hf_root.resolve())
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
print(f"{report['status'].upper()}: wrote {args.output}")
if report["status"] != "pass":
for failure in report["failures"][:40]:
print(f"- {failure['group']}: {failure['surface']} {failure['kind']} {failure['path']}")
if len(report["failures"]) > 40:
print(f"- ... {len(report['failures']) - 40} more failures")
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())