Dracufeuer commited on
Commit
f5ed9fb
·
verified ·
1 Parent(s): ab4d2dd

Sync submission checker docs

Browse files
Files changed (3) hide show
  1. PLAN.md +1 -0
  2. SUBMISSION.md +1 -0
  3. scripts/check_submission_ready.py +156 -0
PLAN.md CHANGED
@@ -113,6 +113,7 @@ All times are `America/Los_Angeles` / PDT unless noted.
113
  - 2026-06-14 01:27: addressed the submission-readiness review by adding hero-name parsing, making Draft Lab demoable, adding tests, preparing a dataset card, declaring Apache-2.0 licensing, and aligning the Modal dependency version.
114
  - 2026-06-14 02:36: continued demo-readiness hardening by adding role-aware recommendation filtering, Bayesian win-rate shrinkage for low samples, pre-game item timing labels, and a repeatable public Space API check script.
115
  - 2026-06-14 02:41: replaced the generic generated adapter README with a DOTA2Tuned-specific model card covering intended behavior, evidence discipline, usage, evaluation notes, limitations, and public links.
 
116
 
117
  ## Adapter Eval Notes
118
 
 
113
  - 2026-06-14 01:27: addressed the submission-readiness review by adding hero-name parsing, making Draft Lab demoable, adding tests, preparing a dataset card, declaring Apache-2.0 licensing, and aligning the Modal dependency version.
114
  - 2026-06-14 02:36: continued demo-readiness hardening by adding role-aware recommendation filtering, Bayesian win-rate shrinkage for low samples, pre-game item timing labels, and a repeatable public Space API check script.
115
  - 2026-06-14 02:41: replaced the generic generated adapter README with a DOTA2Tuned-specific model card covering intended behavior, evidence discipline, usage, evaluation notes, limitations, and public links.
116
+ - 2026-06-14 02:57: added a final submission-readiness checker that verifies public URLs, Space runtime, Hub model/dataset cards, git cleanliness, and all public Gradio API endpoints while listing the human-only video/social/submission steps separately.
117
 
118
  ## Adapter Eval Notes
119
 
SUBMISSION.md CHANGED
@@ -80,6 +80,7 @@ uv run python -c "from app import demo; print(type(demo).__name__, len(demo.bloc
80
  uv run dota2tuned modal-smoke
81
  uv run dota2tuned modal-ask "Suggest one mid hero against Phantom Assassin and Witch Doctor. Include one caveat." --context "Use only grounded advice. Mention that sample sizes and patch context matter." --max-new-tokens 160
82
  uv run python scripts/check_public_space.py
 
83
  curl -L -sS -o /dev/null -w '%{http_code}\n' https://build-small-hackathon-dota2tuned.hf.space
84
  curl -sS -o /dev/null -w '%{http_code}\n' https://dracufeuer--dota2tuned-ui.modal.run
85
  git status --short --branch
 
80
  uv run dota2tuned modal-smoke
81
  uv run dota2tuned modal-ask "Suggest one mid hero against Phantom Assassin and Witch Doctor. Include one caveat." --context "Use only grounded advice. Mention that sample sizes and patch context matter." --max-new-tokens 160
82
  uv run python scripts/check_public_space.py
83
+ uv run python scripts/check_submission_ready.py
84
  curl -L -sS -o /dev/null -w '%{http_code}\n' https://build-small-hackathon-dota2tuned.hf.space
85
  curl -sS -o /dev/null -w '%{http_code}\n' https://dracufeuer--dota2tuned-ui.modal.run
86
  git status --short --branch
scripts/check_submission_ready.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import subprocess
7
+ import sys
8
+ from datetime import UTC, datetime
9
+ from pathlib import Path
10
+ from typing import Any
11
+ from urllib.error import HTTPError, URLError
12
+ from urllib.request import Request, urlopen
13
+
14
+ from check_public_space import DEFAULT_SPACE, run_checks
15
+ from huggingface_hub import HfApi
16
+
17
+ DEFAULT_MODEL_REPO = "build-small-hackathon/dota2tuned-qwen3-4b-2507-lora"
18
+ DEFAULT_DATASET_REPO = "build-small-hackathon/dota2tuned-data"
19
+ DEFAULT_MODAL_URL = "https://dracufeuer--dota2tuned-ui.modal.run"
20
+ DEFAULT_GITHUB_REPO = "https://github.com/1ncompleteness/DOTA2Tuned"
21
+
22
+ MANUAL_ITEMS = [
23
+ "Record short demo video.",
24
+ "Publish social post.",
25
+ "Submit Space link, demo video link, and social post link by June 15, 2026.",
26
+ ]
27
+
28
+
29
+ def _http_status(url: str, *, timeout: int = 30) -> dict[str, Any]:
30
+ request = Request(url, headers={"User-Agent": "DOTA2Tuned submission checker"})
31
+ try:
32
+ with urlopen(request, timeout=timeout) as response:
33
+ return {"ok": 200 <= response.status < 400, "status": response.status}
34
+ except HTTPError as exc:
35
+ return {"ok": False, "status": exc.code, "error": str(exc)}
36
+ except URLError as exc:
37
+ return {"ok": False, "status": None, "error": str(exc.reason)}
38
+
39
+
40
+ def _git_status() -> dict[str, Any]:
41
+ result = subprocess.run(
42
+ ["git", "status", "--short", "--branch"],
43
+ check=False,
44
+ capture_output=True,
45
+ text=True,
46
+ )
47
+ lines = result.stdout.strip().splitlines()
48
+ changed = [line for line in lines[1:] if line.strip()]
49
+ return {
50
+ "ok": result.returncode == 0 and not changed,
51
+ "returncode": result.returncode,
52
+ "status": lines,
53
+ }
54
+
55
+
56
+ def _repo_has_file(api: HfApi, repo_id: str, repo_type: str, filename: str) -> dict[str, Any]:
57
+ try:
58
+ if repo_type == "model":
59
+ info = api.model_info(repo_id)
60
+ elif repo_type == "dataset":
61
+ info = api.dataset_info(repo_id)
62
+ else:
63
+ raise ValueError(f"unsupported repo_type: {repo_type}")
64
+ files = {sibling.rfilename for sibling in info.siblings}
65
+ return {"ok": filename in files, "file": filename, "repo": repo_id}
66
+ except Exception as exc: # pragma: no cover - network smoke script
67
+ return {"ok": False, "file": filename, "repo": repo_id, "error": repr(exc)}
68
+
69
+
70
+ def _space_runtime(api: HfApi, space_id: str) -> dict[str, Any]:
71
+ try:
72
+ info = api.space_info(space_id)
73
+ runtime = getattr(info, "runtime", None)
74
+ stage = getattr(runtime, "stage", str(runtime))
75
+ return {"ok": stage == "RUNNING", "stage": stage, "space": space_id}
76
+ except Exception as exc: # pragma: no cover - network smoke script
77
+ return {"ok": False, "space": space_id, "error": repr(exc)}
78
+
79
+
80
+ def run_submission_checks(args: argparse.Namespace) -> dict[str, Any]:
81
+ token = os.getenv("HF_TOKEN")
82
+ api = HfApi(token=token)
83
+ space_id = args.space_repo
84
+ checks: dict[str, Any] = {
85
+ "git_clean": _git_status(),
86
+ "space_http": _http_status(args.space_url),
87
+ "modal_http": _http_status(args.modal_url),
88
+ "github_http": _http_status(args.github_repo),
89
+ "space_runtime": _space_runtime(api, space_id),
90
+ "model_card": _repo_has_file(api, args.model_repo, "model", "README.md"),
91
+ "dataset_card": _repo_has_file(api, args.dataset_repo, "dataset", "README.md"),
92
+ }
93
+ if not args.skip_public_api:
94
+ public_api = run_checks(args.space_url)
95
+ checks["public_space_api"] = {
96
+ "ok": all(item["status"] == "ok" for item in public_api["checks"]),
97
+ "checks": public_api["checks"],
98
+ }
99
+ return {
100
+ "generated_at": datetime.now(UTC).isoformat(),
101
+ "machine_checks": checks,
102
+ "manual_remaining": MANUAL_ITEMS,
103
+ "links": {
104
+ "space": args.space_url,
105
+ "github": args.github_repo,
106
+ "model": f"https://huggingface.co/{args.model_repo}",
107
+ "dataset": f"https://huggingface.co/datasets/{args.dataset_repo}",
108
+ "modal": args.modal_url,
109
+ },
110
+ }
111
+
112
+
113
+ def _machine_ok(payload: dict[str, Any]) -> bool:
114
+ return all(check.get("ok") is True for check in payload["machine_checks"].values())
115
+
116
+
117
+ def main() -> None:
118
+ parser = argparse.ArgumentParser(description="Run final DOTA2Tuned submission checks.")
119
+ parser.add_argument("--space-url", default=DEFAULT_SPACE)
120
+ parser.add_argument("--space-repo", default="build-small-hackathon/dota2tuned")
121
+ parser.add_argument("--model-repo", default=DEFAULT_MODEL_REPO)
122
+ parser.add_argument("--dataset-repo", default=DEFAULT_DATASET_REPO)
123
+ parser.add_argument("--modal-url", default=DEFAULT_MODAL_URL)
124
+ parser.add_argument("--github-repo", default=DEFAULT_GITHUB_REPO)
125
+ parser.add_argument(
126
+ "--output",
127
+ default="submission_evidence/final_submission_check.json",
128
+ help="Path for JSON evidence output.",
129
+ )
130
+ parser.add_argument(
131
+ "--skip-public-api",
132
+ action="store_true",
133
+ help="Skip Gradio endpoint checks when only public artifact status is needed.",
134
+ )
135
+ args = parser.parse_args()
136
+
137
+ payload = run_submission_checks(args)
138
+ output_path = Path(args.output)
139
+ output_path.parent.mkdir(parents=True, exist_ok=True)
140
+ output_path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
141
+
142
+ print("Machine checks:")
143
+ for name, check in payload["machine_checks"].items():
144
+ detail = check.get("stage") or check.get("status") or check.get("file") or ""
145
+ print(f"- {name}: {'ok' if check.get('ok') else 'fail'} {detail}")
146
+ print("\nManual remaining:")
147
+ for item in payload["manual_remaining"]:
148
+ print(f"- {item}")
149
+ print(f"\nWrote {output_path}")
150
+
151
+ if not _machine_ok(payload):
152
+ sys.exit(1)
153
+
154
+
155
+ if __name__ == "__main__":
156
+ main()