Skip to content

Commit dfa05d1

Browse files
committed
Repair v33 Debian service launch, NLTK resources and uv sandbox interpreter mounts
1 parent c474321 commit dfa05d1

15 files changed

Lines changed: 328 additions & 50 deletions

‎.github/workflows/v100-cpu-validation.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Install isolated test dependencies and CPU Torch
2626
run: |
2727
python -m pip install --index-url https://download.pytorch.org/whl/cpu torch==2.6.0
28-
python -m pip install . pytest==8.4.2 numpy==2.2.6 psutil==7.0.0 safetensors==0.8.0 tomli-w==1.2.0 transformers==5.17.0 peft==0.21.2 accelerate==1.15.0
28+
python -m pip install . pytest==8.4.2 numpy==2.2.6 psutil==7.0.0 safetensors==0.8.0 tomli-w==1.2.0 transformers==5.17.0 peft==0.21.2 accelerate==1.15.0 nltk==3.10.3
2929
- name: Exercise controller, DPO gradients, tensor breeding and tiny model training
3030
env:
3131
PYTEST_DISABLE_PLUGIN_AUTOLOAD: '1'

‎CAMPAIGN.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# V100 campaign v32
1+
# V100 campaign v33
2+
3+
v33 repairs the deployment failures observed on Debian: systemd receives an unquoted absolute `WorkingDirectory` and validates the generated unit before starting it; the first supervisor start keeps the newly prepared configuration instead of reverting to an old failed run. NLTK downloads into an explicitly created, owner-private resource directory without disabling its security enforcement or changing the user's home permissions. Canonical helper migration checks the newly requested 32768 context and retains the old metadata snapshot; actual template, value or manifest changes still fail. Sandbox mounts include intermediate `uv` interpreter symlinks without exposing the whole project/home, and failed hardware probes preserve the full child diagnostic in `sandbox-probe.log`.
24

35
Use `tools/upgrade-v100-campaign.sh RELEASE_COMMIT` on Debian after any existing training/calibration/MTP sweep completes. It updates only the existing isolated continual venv, repairs the launcher atomically, retains checkpoints, prepares optional components, runs mandatory short CUDA/master acceptance probes, and starts the owned supervisor only after those probes pass. Failed acceptance retains a report and leaves the mission stopped. Preparation prints each stage and records failures as `deferred`; a deferred feature is not operational.
46

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "rlms"
33
authors = [
44
{name = "Alex Zhang", email = "altzhang@mit.edu"},
55
]
6-
version = "0.1.3+v100.32"
6+
version = "0.1.3+v100.33"
77
description = "Recursive Language Models."
88
readme = "README.md"
99
license = "MIT"

‎rlm/v100/benchmark_worker.py‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import hashlib
44
import json
5+
import os
6+
import stat
57
import sys
68
from pathlib import Path
79

@@ -10,6 +12,21 @@ def key(row):
1012
return "/".join(str(row[k]) for k in ("category", "task", "question_id"))
1113

1214

15+
def prepare_nltk(folder):
16+
import nltk
17+
18+
# Authorize an existing private data root, rather than asking NLTK to trust
19+
# the snapshot's possibly group-writable parent before creating it.
20+
resources = folder / "nltk"
21+
resources.mkdir(mode=0o700, exist_ok=True)
22+
info = resources.lstat()
23+
if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.geteuid() or info.st_mode & 0o022:
24+
raise ValueError("Official grader resources must use an owned private directory")
25+
for package in ("punkt", "punkt_tab", "averaged_perceptron_tagger_eng"):
26+
if not nltk.download(package, download_dir=str(resources), quiet=True):
27+
raise RuntimeError("Official grader resource download failed: " + package)
28+
29+
1330
def prepare(folder, limit, coding=False):
1431
from datasets import load_dataset
1532
from huggingface_hub import HfApi
@@ -91,11 +108,7 @@ def prepare(folder, limit, coding=False):
91108
indent=2,
92109
)
93110
)
94-
import nltk
95-
96-
for package in ("punkt", "punkt_tab", "averaged_perceptron_tagger_eng"):
97-
if not nltk.download(package, download_dir=str(folder / "nltk"), quiet=True):
98-
raise RuntimeError("Official grader resource download failed: " + package)
111+
prepare_nltk(folder)
99112
# Import during preparation so missing official dependencies fail before GPU work.
100113
from livebench.gen_ground_truth_judgment import play_a_match_gt # noqa: F401
101114

‎rlm/v100/campaign.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def stage(name, function):
104104
print(json.dumps({"campaign": name, **stages[name]}), flush=True)
105105

106106
def helper():
107-
evidence = canonicalize_remote(root)
107+
evidence = canonicalize_remote(root, context_window=32768)
108108
from rlm.v100.competition import helper_client
109109

110110
helper_path = root / "research/researcher-rtx3090.json"

‎rlm/v100/code_lab.py‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# change its algorithms; the host prompt/evaluator/controller stay outside it.
1616
PROMPT_FILES = {
1717
"rlm/v100/hardware_acceptance.py",
18+
"rlm/v100/sandbox_python.py",
1819
"rlm/v100/scratch_master.py",
1920
"rlm/v100/market_adapters.py",
2021
"rlm/v100/architecture_promotion.py",
@@ -226,10 +227,10 @@ def sandbox_command(
226227
"bubblewrap is required; untrusted code never falls back to host execution"
227228
)
228229
args = [bwrap, "--unshare-all", "--die-with-parent", "--new-session", "--cap-drop", "ALL"]
229-
prefixes = [Path("/usr"), Path("/lib"), Path("/lib64"), Path(sys.prefix), Path(sys.base_prefix)]
230-
for path in dict.fromkeys(prefixes):
231-
if path.exists():
232-
args += ["--ro-bind", str(path), str(path)]
230+
from rlm.v100.sandbox_python import runtime_mounts
231+
232+
for path in runtime_mounts():
233+
args += ["--ro-bind", str(path), str(path)]
233234
args += [
234235
"--proc",
235236
"/proc",

‎rlm/v100/hardware_acceptance.py‎

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,29 @@
99
from rlm.v100.common import atomic_json, load_profile
1010

1111

12+
def sandbox_probe(folder: Path) -> dict:
13+
from rlm.v100.code_lab import sandbox_command, sandbox_environment
14+
15+
(folder / "source").mkdir()
16+
(folder / "checks").mkdir()
17+
log = folder / "sandbox-probe.log"
18+
with log.open("w") as stream:
19+
child = subprocess.run(
20+
sandbox_command(folder, [sys.executable, "-I", "-c", "print('sandbox-ok')"]),
21+
env=sandbox_environment(),
22+
timeout=30,
23+
stdout=stream,
24+
stderr=subprocess.STDOUT,
25+
text=True,
26+
)
27+
output = log.read_text()
28+
if child.returncode or output.strip() != "sandbox-ok":
29+
raise RuntimeError(
30+
f"Sandbox probe exit={child.returncode}; log={log}; detail={output[-1000:]}"
31+
)
32+
return {"namespace_execution": True, "network_unshared": True, "log": str(log)}
33+
34+
1235
def run(root: Path, profile_path: Path, desktop: bool = False) -> Path:
1336
from rlm.v100.competition import helper_client, managed_server, require_idle_gpu
1437
from rlm.v100.mission import status
@@ -35,7 +58,7 @@ def check(name, action, required=False):
3558
result["checks"][name] = {
3659
"state": "failed",
3760
"error": type(error).__name__,
38-
"detail": str(error)[:500],
61+
"detail": str(error)[:1500],
3962
}
4063
if required:
4164
result["required_passed"] = False
@@ -94,24 +117,7 @@ def master():
94117

95118
check("master-inference", master, required=True)
96119

97-
def sandbox():
98-
from rlm.v100.code_lab import sandbox_command, sandbox_environment
99-
100-
(folder / "source").mkdir()
101-
(folder / "checks").mkdir()
102-
child = subprocess.run(
103-
sandbox_command(folder, [sys.executable, "-I", "-c", "print('sandbox-ok')"]),
104-
env=sandbox_environment(),
105-
timeout=30,
106-
capture_output=True,
107-
text=True,
108-
check=True,
109-
)
110-
if child.stdout.strip() != "sandbox-ok":
111-
raise ValueError("Sandbox probe returned another result")
112-
return {"namespace_execution": True, "network_unshared": True}
113-
114-
check("private-code-sandbox", sandbox)
120+
check("private-code-sandbox", lambda: sandbox_probe(folder))
115121

116122
def rtx():
117123
path = root / "research/researcher-rtx3090.json"

‎rlm/v100/public_benchmarks.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,10 @@ def grade(root: Path, snapshot: Path, question: dict, answer: dict, folder: Path
109109
"--cap-drop",
110110
"ALL",
111111
]
112-
for path in dict.fromkeys(
113-
[Path("/usr"), Path("/lib"), Path("/lib64"), Path(sys.base_prefix), python.parent.parent]
114-
):
115-
if path.exists():
116-
args += ["--ro-bind", str(path), str(path)]
112+
from rlm.v100.sandbox_python import runtime_mounts
113+
114+
for path in runtime_mounts(python):
115+
args += ["--ro-bind", str(path), str(path)]
117116
args += [
118117
"--proc",
119118
"/proc",

‎rlm/v100/remote_helper.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ def selected_helper(root: Path) -> Path:
538538
return path
539539

540540

541-
def canonicalize_remote(root: Path) -> dict:
541+
def canonicalize_remote(root: Path, context_window: int | None = None) -> dict:
542542
"""Rebind only proven parameter-order/date changes; never silently trust new templates."""
543543
from rlm.v100.common import load_profile
544544
from rlm.v100.competition import helper_client
@@ -549,9 +549,15 @@ def canonicalize_remote(root: Path) -> dict:
549549
path = root / "research/researcher-rtx3090.json"
550550
original = json.loads(path.read_text())
551551
profile = load_profile(path, root)
552+
if context_window is not None:
553+
if type(context_window) is not int or not 4096 <= context_window <= 262144:
554+
raise ValueError("Invalid migration context budget")
555+
profile["runtime"]["context_window"] = context_window
556+
profile["server"]["context_per_slot"] = context_window
552557
client = helper_client(profile, root)
553558
if client.metadata_hash_scheme == ORDERED_METADATA:
554559
client.identity()
560+
client.loaded()
555561
return {"status": "canonical identity verified"}
556562
snapshot = Path(profile["resources"]["metadata_snapshot"])
557563
if not snapshot.is_absolute():
@@ -572,6 +578,9 @@ def canonicalize_remote(root: Path) -> dict:
572578
metadata_sha256=metadata_sha(info, ORDERED_METADATA),
573579
metadata_snapshot=str((audit / "show.json").relative_to(root)),
574580
)
581+
if context_window is not None:
582+
original["runtime"]["context_window"] = context_window
583+
original["server"]["context_per_slot"] = context_window
575584
validate_remote(original)
576585
atomic_json(path, original)
577586
return {

‎rlm/v100/research_sandbox.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ def command(root: Path, source: Path, work: Path, broker: Path) -> list[str]:
5151
"ALL",
5252
"--clearenv",
5353
]
54-
for path in dict.fromkeys(
55-
[Path("/usr"), Path("/lib"), Path("/lib64"), Path(sys.prefix), Path(sys.base_prefix)]
56-
):
57-
if path.exists():
58-
args += ["--ro-bind", str(path), str(path)]
54+
from rlm.v100.sandbox_python import runtime_mounts
55+
56+
for path in runtime_mounts():
57+
args += ["--ro-bind", str(path), str(path)]
5958
return args + [
6059
"--proc",
6160
"/proc",

0 commit comments

Comments
 (0)