v0.4.5: restore tooling lost with sandbox reset
Browse files- scripts/new_t4_bootstrap.py +129 -0
scripts/new_t4_bootstrap.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Bootstrap the NEW T4 instance end-to-end (replaces the timed-out one).
|
| 3 |
+
|
| 4 |
+
Usage: T4_URL=<new-tunnel> python3 scripts/new_t4_bootstrap.py
|
| 5 |
+
|
| 6 |
+
Steps (all idempotent):
|
| 7 |
+
1. sanity-check the envelope
|
| 8 |
+
2. upload qwenjev_code.tgz + unpack into /content/qwenjev
|
| 9 |
+
3. pip install arc-agi, upgrade torchao, write HF token
|
| 10 |
+
4. launch remote re-collection (24 games x 10 eps, nohup)
|
| 11 |
+
5. launch ops/t4_real25.py orchestrator (nohup) — its prep stage runs
|
| 12 |
+
immediately (HF pull v2 adapter), data stage rebuilds dataset_remote
|
| 13 |
+
if the collector is still running... NOTE: we wait for collection by
|
| 14 |
+
launching the orchestrator AFTER collection finishes; use mode=lite to
|
| 15 |
+
train on the local-only dataset right away instead.
|
| 16 |
+
"""
|
| 17 |
+
import os
|
| 18 |
+
import sys
|
| 19 |
+
|
| 20 |
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "ops"))
|
| 21 |
+
import t4exec # noqa: E402
|
| 22 |
+
|
| 23 |
+
TOKEN = os.environ.get("HF_TOKEN") # never hardcode; pass via env
|
| 24 |
+
CODE_TGZ = os.environ.get("CODE_TGZ", "/tmp/qwenjev_code.tgz")
|
| 25 |
+
MODE = os.environ.get("MODE", "full") # full = wait for re-collection
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def run(code, timeout=120):
|
| 29 |
+
r = t4exec.execute(code, timeout=timeout)
|
| 30 |
+
out = r.get("stdout", "")
|
| 31 |
+
if not out.strip():
|
| 32 |
+
raise RuntimeError(f"empty response: { {k: str(v)[:120] for k, v in r.items()} }")
|
| 33 |
+
return out
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def main():
|
| 37 |
+
assert TOKEN, "export HF_TOKEN=<hf write token> first"
|
| 38 |
+
print("== 1. envelope sanity ==")
|
| 39 |
+
print(run("print('envelope ok')").strip())
|
| 40 |
+
|
| 41 |
+
print("== 2. code upload ==")
|
| 42 |
+
t4exec.put(CODE_TGZ, "/content/qwenjev_code.tgz", timeout=300)
|
| 43 |
+
run("""
|
| 44 |
+
import tarfile, os, shutil
|
| 45 |
+
os.makedirs('/content/qwenjev', exist_ok=True)
|
| 46 |
+
with tarfile.open('/content/qwenjev_code.tgz') as t:
|
| 47 |
+
t.extractall('/content/qwenjev')
|
| 48 |
+
os.remove('/content/qwenjev_code.tgz')
|
| 49 |
+
print('unpacked:', os.path.isdir('/content/qwenjev/ops'))
|
| 50 |
+
""")
|
| 51 |
+
|
| 52 |
+
print("== 3. deps ==")
|
| 53 |
+
run("""
|
| 54 |
+
import subprocess
|
| 55 |
+
r = subprocess.run(['bash','-c',
|
| 56 |
+
'pip install -q arc-agi 2>&1 | tail -1; pip install -q -U torchao 2>&1 | tail -1'],
|
| 57 |
+
capture_output=True, text=True, timeout=300)
|
| 58 |
+
print('deps done')
|
| 59 |
+
""", timeout=420)
|
| 60 |
+
run(f"""
|
| 61 |
+
import os
|
| 62 |
+
os.makedirs('/content/qwenjev_work_v3/logs', exist_ok=True)
|
| 63 |
+
os.makedirs('/content/qwenjev_work_v3/done_v3', exist_ok=True)
|
| 64 |
+
open('/content/qwenjev_work_v3/.hf_token','w').write({TOKEN!r})
|
| 65 |
+
print('dirs+token ok')
|
| 66 |
+
""")
|
| 67 |
+
|
| 68 |
+
print("== 4. remote re-collection ==")
|
| 69 |
+
run("""
|
| 70 |
+
import subprocess
|
| 71 |
+
p = subprocess.Popen(['bash','-c',
|
| 72 |
+
'cd /content/qwenjev && nohup python3 -u data/collect_selfplay.py '
|
| 73 |
+
'--config configs/collect_real24.yaml > /content/collect_v3.log 2>&1 < /dev/null &'],
|
| 74 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)
|
| 75 |
+
print('collect launched')
|
| 76 |
+
""")
|
| 77 |
+
|
| 78 |
+
print("== 5. orchestrator handoff ==")
|
| 79 |
+
if MODE == "full":
|
| 80 |
+
# chain daemon: polls the collect log, launches the orchestrator
|
| 81 |
+
# the moment collection finishes — fully unattended.
|
| 82 |
+
run("""
|
| 83 |
+
import subprocess
|
| 84 |
+
p = subprocess.Popen(['bash','-c',
|
| 85 |
+
'cd /content/qwenjev && nohup python3 -u scripts/remote_chain.py > /content/chain.log 2>&1 < /dev/null &'],
|
| 86 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)
|
| 87 |
+
print('chain daemon on')
|
| 88 |
+
""")
|
| 89 |
+
elif MODE == "lite":
|
| 90 |
+
# train on the local-only dataset (HF tgz) right away; the data
|
| 91 |
+
# stage of t4_real25.py reuses dataset_remote if present else
|
| 92 |
+
# rebuilds it — for lite mode we let it build from traces (still
|
| 93 |
+
# collecting) is NOT ok; so we pre-seed dataset_remote from HF.
|
| 94 |
+
run("""
|
| 95 |
+
import subprocess
|
| 96 |
+
p = subprocess.Popen(['bash','-c',
|
| 97 |
+
'cd /content/qwenjev && python3 - <<EOF > /tmp/seed.log 2>&1\\n'
|
| 98 |
+
'import tarfile\\n'
|
| 99 |
+
'from huggingface_hub import hf_hub_download\\n'
|
| 100 |
+
'tgz = hf_hub_download("tchbcb/qwenjev", "t4_assets_v3/data/dataset_v3_local.tgz")\\n'
|
| 101 |
+
'with tarfile.open(tgz) as t: t.extractall("data/")\\n'
|
| 102 |
+
'import shutil, os\\n'
|
| 103 |
+
'shutil.move("data/dataset_v3", "data/dataset_remote")\\n'
|
| 104 |
+
'print("seeded")\\nEOF'
|
| 105 |
+
' && cp /tmp/seed.log /content/seed_done.log'],
|
| 106 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)
|
| 107 |
+
print('seeding local dataset as dataset_remote (async)')
|
| 108 |
+
""")
|
| 109 |
+
else:
|
| 110 |
+
run("""
|
| 111 |
+
import subprocess
|
| 112 |
+
p = subprocess.Popen(['bash','-c',
|
| 113 |
+
'cd /content/qwenjev && nohup python3 -u -B t4_real25.py > /content/t4_v3.log 2>&1 < /dev/null &'],
|
| 114 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)
|
| 115 |
+
print('orchestrator launched (lite)')
|
| 116 |
+
""")
|
| 117 |
+
# watchdog: auto control-eval after ALL_DONE (both modes)
|
| 118 |
+
run("""
|
| 119 |
+
import subprocess
|
| 120 |
+
p = subprocess.Popen(['bash','-c',
|
| 121 |
+
'cd /content/qwenjev && nohup python3 -u watchdog_eval_v3.py > /content/watchdog.log 2>&1 < /dev/null &'],
|
| 122 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True)
|
| 123 |
+
print('watchdog on')
|
| 124 |
+
""")
|
| 125 |
+
print("BOOTSTRAP_DONE")
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
if __name__ == "__main__":
|
| 129 |
+
main()
|