phase4_prep: pins at a813e5c7 + bounded-readback rehearsal stage / tee-prefix fix
Browse files- kernels/phase4_prep.py +86 -5
kernels/phase4_prep.py
CHANGED
|
@@ -13,18 +13,18 @@ import hashlib, json, os, subprocess, sys, time
|
|
| 13 |
|
| 14 |
os.chdir("/kaggle/working")
|
| 15 |
sys.path.insert(0, "/kaggle/working")
|
| 16 |
-
REV = os.environ.get("OUNCE100M_REV") or "
|
| 17 |
WANT = {
|
| 18 |
"ounce100m_credentials.py": ("ounce100m_credentials.py",
|
| 19 |
"6525f62f03f2d73650a1eb4f70fcb52d1194caad4ca88b2d8bd8fd54f88339b6"),
|
| 20 |
"shard_dataset.py": ("train/shard_dataset.py",
|
| 21 |
"f35653bf4c8f2cfe7bb0c2c7835e308505fb5a84b4eb002d0f82f2cada768ca6"),
|
| 22 |
"hubckpt.py": ("train/hubckpt.py",
|
| 23 |
-
"
|
| 24 |
"train_ounce100m.py": ("train/train_ounce100m.py",
|
| 25 |
"744259c7519e5a12c2d2bf4dca534fa39f7ddb7e6689e1a5a9e0925bfaa640aa"),
|
| 26 |
"phase4_session.py": ("kernels/phase4_session.py",
|
| 27 |
-
"
|
| 28 |
}
|
| 29 |
BASE = "https://huggingface.co/Cion-lab/ounce100m-code/resolve/" + REV
|
| 30 |
for p, (rp, want) in sorted(WANT.items()):
|
|
@@ -219,6 +219,87 @@ rc3, _ = run([sys.executable, "-c",
|
|
| 219 |
"print('TRAINER_HELP_RC', p.returncode, 'lines', len((p.stdout or '').splitlines()))\n"
|
| 220 |
"assert p.returncode == 0, (p.stdout or '')[-1500:] + (p.stderr or '')[-1500:]\n"],
|
| 221 |
"CURSOR_AND_IMPORT", 900)
|
| 222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
"seconds", round(time.time() - T0, 1), flush=True)
|
| 224 |
-
raise SystemExit(0 if (rc1 == rc2 == rc3 == 0) else 4)
|
|
|
|
| 13 |
|
| 14 |
os.chdir("/kaggle/working")
|
| 15 |
sys.path.insert(0, "/kaggle/working")
|
| 16 |
+
REV = os.environ.get("OUNCE100M_REV") or "a813e5c7fb7539a0586756c76b95f7520934f7a0"
|
| 17 |
WANT = {
|
| 18 |
"ounce100m_credentials.py": ("ounce100m_credentials.py",
|
| 19 |
"6525f62f03f2d73650a1eb4f70fcb52d1194caad4ca88b2d8bd8fd54f88339b6"),
|
| 20 |
"shard_dataset.py": ("train/shard_dataset.py",
|
| 21 |
"f35653bf4c8f2cfe7bb0c2c7835e308505fb5a84b4eb002d0f82f2cada768ca6"),
|
| 22 |
"hubckpt.py": ("train/hubckpt.py",
|
| 23 |
+
"a21de427b9c7586d3cc104e80d230a085d00907829fe1148d0b1ddbec9f4d20a"),
|
| 24 |
"train_ounce100m.py": ("train/train_ounce100m.py",
|
| 25 |
"744259c7519e5a12c2d2bf4dca534fa39f7ddb7e6689e1a5a9e0925bfaa640aa"),
|
| 26 |
"phase4_session.py": ("kernels/phase4_session.py",
|
| 27 |
+
"925ef1f160dcd7ae52090d10fbb7e8abca1f52f3b087d36a6fc35fad8a5de6e1"),
|
| 28 |
}
|
| 29 |
BASE = "https://huggingface.co/Cion-lab/ounce100m-code/resolve/" + REV
|
| 30 |
for p, (rp, want) in sorted(WANT.items()):
|
|
|
|
| 219 |
"print('TRAINER_HELP_RC', p.returncode, 'lines', len((p.stdout or '').splitlines()))\n"
|
| 220 |
"assert p.returncode == 0, (p.stdout or '')[-1500:] + (p.stderr or '')[-1500:]\n"],
|
| 221 |
"CURSOR_AND_IMPORT", 900)
|
| 222 |
+
|
| 223 |
+
# Stage 4 -- checkpoint verification against real Hub bytes, on the theory that a gate which authorises
|
| 224 |
+
# deleting the only local copy of a checkpoint should be tested where failing is free. Probe v5 measured
|
| 225 |
+
# the old whole-object read-back at `push+verify=797.7s` for an 850 MB optimizer.pt (and 26 s for the same
|
| 226 |
+
# cycle once the CDN was warm), so the read-back is now two bounded Range requests; this proves the
|
| 227 |
+
# replacement still says yes to the 1.27 GB the probe really pushed and still says no three different ways.
|
| 228 |
+
# PREP_VERIFY_REPO exists because the probe repos are scratch: point it at `Cion-lab/ounce100m-ckpt` plus a
|
| 229 |
+
# `ckpt/checkpoint-N` once the run has one and this stage outlives them.
|
| 230 |
+
VERIFY = """
|
| 231 |
+
import json, os, sys, time
|
| 232 |
+
sys.path.insert(0, "/kaggle/working")
|
| 233 |
+
import hubckpt
|
| 234 |
+
from huggingface_hub import snapshot_download
|
| 235 |
+
REPO = os.environ.get("PREP_VERIFY_REPO") or "Cion-lab/ounce100m-ckpt-probe-0920-0747"
|
| 236 |
+
SUB = os.environ.get("PREP_VERIFY_SUB") or "ckpt/checkpoint-10"
|
| 237 |
+
d = "/kaggle/working/verify_subject"
|
| 238 |
+
t0 = time.time()
|
| 239 |
+
snapshot_download(repo_id=REPO, repo_type="dataset", allow_patterns=SUB + "/*", local_dir=d,
|
| 240 |
+
max_workers=4)
|
| 241 |
+
local = os.path.join(d, SUB)
|
| 242 |
+
print("GOT", len(os.listdir(local)), "files from", REPO, SUB, "in", round(time.time() - t0, 1), "s",
|
| 243 |
+
flush=True)
|
| 244 |
+
assert os.path.exists(os.path.join(local, "model.safetensors")), sorted(os.listdir(local))
|
| 245 |
+
|
| 246 |
+
t0 = time.time()
|
| 247 |
+
v = hubckpt.verify_checkpoint(REPO, local, SUB, repo_type="dataset")
|
| 248 |
+
secs = round(time.time() - t0, 1)
|
| 249 |
+
print("VERIFY_CLEAN ok", v["ok"], "readback_ok", v["readback_ok"], "seconds", secs,
|
| 250 |
+
json.dumps({k: v[k] for k in ("n_local", "n_hub", "missing", "mismatch", "extra", "readback")},
|
| 251 |
+
default=str)[:600], flush=True)
|
| 252 |
+
assert v["ok"] and v["readback_ok"], v
|
| 253 |
+
assert secs < 180, f"verification took {secs}s -- the bounded read-back was supposed to make this cheap"
|
| 254 |
+
rb = v["readback"]
|
| 255 |
+
assert rb["path"] == "optimizer.pt" and rb["bytes"] < (10 << 20) and len(rb["ranges"]) == 2, rb
|
| 256 |
+
|
| 257 |
+
# 1. A byte the Hub does not have: the local sha256 stops matching the stored lfs.oid.
|
| 258 |
+
p = os.path.join(local, "optimizer.pt")
|
| 259 |
+
with open(p, "r+b") as fh:
|
| 260 |
+
fh.seek(500_000_001)
|
| 261 |
+
b = fh.read(1)
|
| 262 |
+
fh.seek(500_000_001)
|
| 263 |
+
fh.write(bytes([b[0] ^ 0xFF]))
|
| 264 |
+
v2 = hubckpt.verify_checkpoint(REPO, local, SUB, repo_type="dataset")
|
| 265 |
+
print("VERIFY_TAMPERED ok", v2["ok"], "mismatch", json.dumps(v2["mismatch"])[:260], flush=True)
|
| 266 |
+
assert not v2["ok"] and v2["mismatch"], "a flipped byte at 500 MB verified clean"
|
| 267 |
+
with open(p, "r+b") as fh:
|
| 268 |
+
fh.seek(500_000_001)
|
| 269 |
+
fh.write(b)
|
| 270 |
+
assert hubckpt.verify_checkpoint(REPO, local, SUB, repo_type="dataset")["ok"], "restoring did not help"
|
| 271 |
+
|
| 272 |
+
# 2. A path that is not on the Hub at all: nothing listed means nothing verified.
|
| 273 |
+
v3 = hubckpt.verify_checkpoint(REPO, local, "ckpt/checkpoint-99999999", repo_type="dataset")
|
| 274 |
+
print("VERIFY_ABSENT ok", v3["ok"], "missing", len(v3["missing"]), "of", v3["n_local"], flush=True)
|
| 275 |
+
assert not v3["ok"] and len(v3["missing"]) == v3["n_local"], v3["missing"][:3]
|
| 276 |
+
|
| 277 |
+
# 3. A server that ignores Range and streams the whole object: the read-back must fail rather than pay
|
| 278 |
+
# for 850 MB, because a silent full download is the thing this change exists to prevent.
|
| 279 |
+
real = hubckpt.urllib.request.urlopen
|
| 280 |
+
class _Whole:
|
| 281 |
+
status = 200
|
| 282 |
+
def __enter__(self): return self
|
| 283 |
+
def __exit__(self, *a): return False
|
| 284 |
+
def read(self, n=-1): return b"x" * (len(self) if n is None or n < 0 else min(n, len(self)))
|
| 285 |
+
def __len__(self): return 1 << 20
|
| 286 |
+
def _fake(req, *a, **k):
|
| 287 |
+
# Only the download path is faked: hub_listing uses the same urlopen, and breaking it here would
|
| 288 |
+
# report a "server ignored Range" test as a listing crash.
|
| 289 |
+
if "/resolve/" in getattr(req, "full_url", str(req)):
|
| 290 |
+
return _Whole()
|
| 291 |
+
return real(req, *a, **k)
|
| 292 |
+
hubckpt.urllib.request.urlopen = _fake
|
| 293 |
+
try:
|
| 294 |
+
v4 = hubckpt.verify_checkpoint(REPO, local, SUB, repo_type="dataset")
|
| 295 |
+
finally:
|
| 296 |
+
hubckpt.urllib.request.urlopen = real
|
| 297 |
+
print("VERIFY_NO_206 ok", v4["ok"], "readback", json.dumps(v4["readback"])[:260], flush=True)
|
| 298 |
+
assert not v4["ok"] and "206" in str(v4["readback"]), v4["readback"]
|
| 299 |
+
print("VERIFY_STAGE_OK all four paths behave", flush=True)
|
| 300 |
+
"""
|
| 301 |
+
open("prepverify.py", "w").write(VERIFY)
|
| 302 |
+
rc4, _ = run([sys.executable, "prepverify.py"], "CHECK_VERIFY", 1800, env=dict(PLANENV))
|
| 303 |
+
print("VERDICT PHASE4_PREP rc_launcher", rc1, "rc_check", rc2, "rc_cursor", rc3, "rc_verify", rc4,
|
| 304 |
"seconds", round(time.time() - T0, 1), flush=True)
|
| 305 |
+
raise SystemExit(0 if (rc1 == rc2 == rc3 == rc4 == 0) else 4)
|