opensysone / source /scripts /fleet_campaign.py
andyshu's picture
Back up verified OpenSysOne training snapshot and pinned source
1a0a7fb verified
Raw History Blame Contribute Delete
33.7 kB
"""Deadline-bounded validation-only selection across independent SSH campaigns.
Launch: python scripts/fleet_campaign.py --plan /absolute/fleet-plan.json
Inspect/stop: python scripts/fleet_campaign.py --campaign /absolute/run --status [--stop]
A stopped coordinator can resume with --campaign RUN --resume; selection is frozen
once selection.json exists. Candidate campaigns have their own training deadlines.
"""
import argparse
from collections import defaultdict
from datetime import datetime, timezone
import fcntl
import hashlib
import json
import math
import os
from pathlib import Path
import re
import shlex
import shutil
import signal
import statistics
import subprocess
import sys
import time
import urllib.request
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from scripts import launch_24h as runner
from selection import SELECTION_METRIC, validation_selection
RUN_ROOT = Path.home() / 'ai/opensysone/runs'
SSH = ['ssh', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=8', '-o',
'ServerAliveInterval=5', '-o', 'ServerAliveCountMax=2', '-o', 'StrictHostKeyChecking=yes']
SMALL_FILES = ('manifest.json', 'data_filter.json', 'summary.json',
'correctness_initial.json', 'correctness_final.json')
PROTECTED_SPLITS = ('validation', 'calibration', 'test', 'holdout')
def utc():
return datetime.now(timezone.utc).isoformat()
def checksum(path):
digest = hashlib.sha256()
with Path(path).open('rb') as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b''):
digest.update(chunk)
return digest.hexdigest()
def timestamp(value):
parsed = datetime.fromisoformat(value.replace('Z', '+00:00'))
if parsed.tzinfo is None:
raise ValueError('Deadlines must include an explicit timezone')
return parsed.timestamp()
def validate_plan(plan, now=None):
now = time.time() if now is None else now
cutoff, deadline = timestamp(plan['selection_cutoff']), timestamp(plan['final_deadline'])
if deadline - cutoff < 7200:
raise ValueError('Reserve at least two hours after selection for finalization')
if deadline <= now or deadline > now + 24 * 3600 + 10:
raise ValueError('Final deadline must be future and at most 24 hours away')
if not 1 <= plan.get('port', 18081) <= 65535:
raise ValueError('Invalid API port')
if not 1 <= plan.get('inference_max_tokens', 1024) <= 32768:
raise ValueError('Invalid inference token limit')
for field in ('dataset', 'reference_predictions'):
if not Path(plan[field]).is_absolute():
raise ValueError(f'{field} must be absolute')
if plan.get('reference_sha256') and checksum(plan['reference_predictions']) != plan['reference_sha256']:
raise ValueError('Frozen reference-validation checksum mismatch')
names = set()
for candidate in plan['candidates']:
name, host = candidate['name'], candidate.get('host', 'local')
if not re.fullmatch(r'[a-zA-Z0-9_-]+', name) or name in names:
raise ValueError('Candidate names must be unique safe path components')
names.add(name)
if not re.fullmatch(r'[a-zA-Z0-9_.@-]+', host) or host.startswith('-'):
raise ValueError('Invalid SSH host')
for field in ('project', 'python', 'campaign', 'training'):
if not Path(candidate[field]).is_absolute():
raise ValueError(f'Candidate {field} must be absolute')
if 'dataset' in candidate:
verify_candidate_dataset(candidate, plan, candidate['dataset'])
for directory in candidate.get('evidence_dirs', []):
if not Path(directory).is_absolute():
raise ValueError('Evidence directory must be absolute')
if not names or not any(c.get('host', 'local') == 'local' for c in plan['candidates']):
raise ValueError('Include a local GX10 candidate as the reachable fallback')
return cutoff, deadline
def verify_candidate_dataset(candidate, plan, actual_dataset):
"""Only explicitly registered train-only dataset changes are comparable."""
expected = Path(candidate.get('dataset', plan['dataset']))
if not expected.is_absolute():
raise ValueError('Candidate dataset override must be absolute')
if Path(actual_dataset) != expected:
raise ValueError('Candidate uses an unregistered or incorrect dataset location')
if 'dataset' not in candidate:
return None # Historical candidates retain their exact original behavior.
baseline = Path(plan['dataset'])
manifests = {path: json.loads((path/'manifest.json').read_text()) for path in (baseline, expected)}
protected = {}
for split in PROTECTED_SPLITS:
hashes = []
for path in (baseline, expected):
recorded = manifests[path].get('split_sha256', {}).get(split)
if not isinstance(recorded, str) or not re.fullmatch(r'[0-9a-f]{64}', recorded):
raise ValueError('Dataset lacks protected split checksum: ' + split)
source = path/f'{split}.jsonl'
if not source.is_file() or checksum(source) != recorded:
raise ValueError('Protected split source hash mismatch: ' + split)
hashes.append(recorded)
if hashes[0] != hashes[1]:
raise ValueError('Dataset override changes protected split: ' + split)
protected[split] = hashes[0]
return {'dataset': str(expected), 'reference_dataset': str(baseline),
'protected_split_sha256': protected,
'scope': 'Only training data may differ; protected source bytes verified without reading labels or predictions'}
def verify_selected_dataset(selected, plan):
candidates = [candidate for candidate in plan['candidates'] if candidate['name'] == selected['name']]
if len(candidates) != 1:
raise ValueError('Selected candidate is not uniquely registered in the fleet plan')
return verify_candidate_dataset(candidates[0], plan, selected['config']['dataset'])
def identity(rows):
result = {}
for row in rows:
key = row['id']
if key in result:
raise ValueError('Duplicate validation ID')
result[key] = (row['group'], row['family'], row['target'], row['choices'])
return result
def validation_score(rows, reference):
if len(rows) != 512 or identity(rows) != identity(reference):
raise ValueError('Selection requires the identical 512 validation decisions')
grouped = defaultdict(list)
correct = 0
for row in rows:
logits, probabilities, logs = row['logits'], row['probabilities'], row['log_probabilities']
target = row['target']
if not isinstance(target, int) or isinstance(target, bool):
raise ValueError('Invalid target index')
if len(logits) < 2 or not 0 <= target < len(logits):
raise ValueError('Invalid candidate count/target')
if len(probabilities) != len(logits) or len(logs) != len(logits) or len(row['choices']) != len(logits):
raise ValueError('Inconsistent prediction vector lengths')
if any(not isinstance(v, (int, float)) or not math.isfinite(v)
for values in (logits, probabilities, logs) for v in values):
raise ValueError('Non-finite predictions')
maximum = max(logits)
logsum = math.log(sum(math.exp(v - maximum) for v in logits))
expected_logs = [v - maximum - logsum for v in logits]
expected_probabilities = [math.exp(v) for v in expected_logs]
if any(p < 0 or p > 1 for p in probabilities) or abs(sum(probabilities) - 1) > 2e-6:
raise ValueError('Invalid probabilities')
if any(abs(a-b) > 2e-5 for a,b in zip(logs, expected_logs)) or any(
abs(a-b) > 2e-6 for a,b in zip(probabilities, expected_probabilities)):
raise ValueError('Saved probabilities/log probabilities disagree with logits')
grouped[row['family']].append(-expected_logs[target])
correct += max(range(len(logits)), key=logits.__getitem__) == target
if len(grouped) != 4 or any(len(values) != 128 for values in grouped.values()):
raise ValueError('Expected four validation families with 128 decisions each')
return {'macro_nll': statistics.mean(statistics.mean(v) for v in grouped.values()),
'accuracy': correct / len(rows), 'count': len(rows),
'per_family_nll': {k: statistics.mean(v) for k,v in grouped.items()}}
def verify_candidate(saved, predictions, reference):
if saved.get('format') != 'opensysone-adapter-v1' or not saved.get('trainable_state'):
raise ValueError('Missing durable trained artifact')
if 'temperature' in saved:
raise ValueError('Selection requires the raw validation-trained artifact')
score = validation_score(predictions, reference)
stored = saved['best_validation_macro_nll']
if not math.isfinite(stored) or abs(score['macro_nll'] - stored) > 2e-5:
raise ValueError('Validation score does not match the durable best checkpoint')
if saved['config'].get('validation_per_family') != 128:
raise ValueError('Checkpoint was not selected on all 512 validation decisions')
if saved.get('selection_metric') != SELECTION_METRIC:
raise ValueError('Checkpoint selection policy is unsupported; legacy raw-NLL artifacts require migration')
selected = validation_selection(predictions)
stored_selection = saved.get('best_validation_selection_score')
if not isinstance(stored_selection,(int,float)) or not math.isfinite(stored_selection) or abs(
selected['score'] - stored_selection) > 1e-8:
raise ValueError('Crossfit selection score does not match the durable best checkpoint')
score.update(selection_metric=SELECTION_METRIC,selection_score=selected['score'],selection=selected)
return score
def choose_candidate(eligible):
complete = [row for row in eligible if row.get('eligible') is True]
if not complete:
raise RuntimeError('No verified durable candidate is eligible')
return min(complete, key=lambda row: (row['metrics']['selection_score'], row['name']))
def verify_correctness(directory):
expected = {'branch_chunks_1_probability_max_abs', 'branch_chunks_2_probability_max_abs',
'branch_chunks_4_probability_max_abs', 'question_isolation_probability_max_abs',
'candidate_permutation_probability_max_abs', 'repeat_probability_max_abs'}
final = directory/'correctness_final.json'
path = final if final.exists() else directory/'correctness_initial.json'
if not path.exists():
raise ValueError('Candidate lacks its source-run FP32 correctness evidence')
checks = json.loads(path.read_text())
tolerance = checks.get('tolerance_probability_abs')
if not expected.issubset(checks) or not isinstance(tolerance,(int,float)) or not 0 < tolerance <= 1e-4:
raise ValueError('Incomplete or weakened FP32 correctness gate')
if any(not isinstance(value,(int,float)) or not math.isfinite(value) or not 0 <= value <= tolerance
for key,value in checks.items() if key.endswith('max_abs')):
raise ValueError('Candidate failed FP32 correctness gate')
return path
def verify_compatibility(saved):
from training_model import ADAPTER_VERSION, PROMPT_VERSION
if saved.get('adapter_version') != ADAPTER_VERSION or saved.get('prompt_version') != PROMPT_VERSION:
raise ValueError('Artifact prompt/adapter implementation is incompatible')
dataset = Path(saved['config']['dataset'])
manifest = json.loads((dataset/'manifest.json').read_text())
# Hash opaque source files for provenance; never parse reserved split labels
# or predictions when selecting candidates.
for split,expected in manifest['split_sha256'].items():
if checksum(dataset/f'{split}.jsonl') != expected:
raise ValueError('Frozen dataset source hash mismatch: ' + split)
signature = hashlib.sha256(json.dumps({'data':manifest['split_sha256'],
'model':saved['model_provenance'],'implementation':checksum(ROOT/'training_model.py'),
'max_tokens':saved['config']['max_tokens']},sort_keys=True).encode()).hexdigest()
if signature != saved['data_signature']:
raise ValueError('Artifact dataset/model/implementation signature is incompatible')
def command_on(candidate, arguments, timeout=30):
command = arguments if candidate.get('host', 'local') == 'local' else [
*SSH, candidate['host'], shlex.join(arguments)]
result = subprocess.run(command, capture_output=True, text=True, timeout=timeout)
if result.returncode:
raise RuntimeError(f'{candidate["name"]}: command exited {result.returncode}: {result.stderr[-1500:]}')
return result.stdout
def candidate_status(candidate, stop=False):
arguments = [candidate['python'], str(Path(candidate['project'])/'scripts/campaign_status.py'),
'--campaign', candidate['campaign']]
if stop:
arguments.append('--stop')
output = command_on(candidate, arguments)
# The stop helper emits one explanatory line before its JSON object.
return json.loads(output[output.index('{'):])
def stop_candidate(candidate):
report = candidate_status(candidate)
end = time.monotonic() + 100
while any(report.get(k) for k in ('supervisor_running', 'child_running', 'api_running')):
if time.monotonic() >= end:
raise RuntimeError('Recorded campaign did not stop within 100 seconds')
try:
candidate_status(candidate, stop=True)
except Exception:
# The independent training deadline can end the supervisor between
# inspection and TERM. Accept only a fresh, verified stopped state.
report = candidate_status(candidate)
if not any(report.get(k) for k in ('supervisor_running', 'child_running', 'api_running')):
return report
raise
time.sleep(5)
report = candidate_status(candidate)
return report
def copy_evidence(candidate, source, destination, include_best=False):
destination.mkdir(parents=True, exist_ok=False)
patterns = [*SMALL_FILES, 'best_validation_predictions.json', 'initial_validation_predictions.json', 'resumed_initial_predictions.json',
'validation_step_*_predictions.json']
if include_best:
patterns.append('best.pt')
if candidate.get('host', 'local') == 'local':
for pattern in patterns:
for path in Path(source).glob(pattern):
if path.is_file():
shutil.copy2(path, destination/path.name)
else:
command = ['rsync', '-a', '--protect-args', '--timeout=60', '-e', shlex.join(SSH)]
command.extend('--include=' + pattern for pattern in patterns)
command.extend(['--exclude=*', candidate['host'] + ':' + source.rstrip('/') + '/', str(destination) + '/'])
subprocess.run(command, check=True, capture_output=True, text=True, timeout=180)
def snapshot_candidate(candidate, destination, reference):
import torch
destination.mkdir(parents=True, exist_ok=False)
remote_best = str(Path(candidate['training'])/'best.pt')
before = command_on(candidate, ['sha256sum', remote_best]).split()[0]
copy_evidence(candidate, candidate['training'], destination/'training', include_best=True)
correctness_path = verify_correctness(destination/'training')
for index,directory in enumerate(candidate.get('evidence_dirs', [])):
copy_evidence(candidate, directory, destination/f'evidence_{index}')
checkpoint = destination/'training/best.pt'
after = command_on(candidate, ['sha256sum', remote_best]).split()[0]
if before != after or checksum(checkpoint) != before:
raise ValueError('Candidate checkpoint changed during snapshot or transfer')
saved = torch.load(checkpoint, map_location='cpu', weights_only=False)
verify_compatibility(saved)
step = saved['step']
expected_name = f'validation_step_{step:06d}_predictions.json' if step else 'initial_validation_predictions.json'
files = list(destination.glob('*/best_validation_predictions.json')) + list(destination.glob('*/' + expected_name))
# Never use a resumed initial prediction without proof of its original step.
# Inherited best artifacts require their parent's named validation evidence.
verified = []
errors = []
for path in files:
try:
predictions = json.loads(path.read_text())
metrics = verify_candidate(saved, predictions, reference)
verified.append((path, metrics))
except (KeyError, TypeError, ValueError) as error:
errors.append(str(error))
if not verified:
raise ValueError('Durable best has no matching complete validation evidence: ' + '; '.join(errors))
evidence, metrics = verified[0]
model_path = Path(saved['config']['model'])
if not model_path.is_dir():
raise ValueError('Pinned base model is not available at the saved GX10 path')
if json.loads((model_path/'opensysone-provenance.json').read_text()) != saved['model_provenance']:
raise ValueError('Available GX10 base model pin does not match the artifact')
record = {'name': candidate['name'], 'host': candidate.get('host', 'local'), 'eligible': True,
'source_campaign': candidate['campaign'], 'source_training': candidate['training'],
'checkpoint': str(checkpoint), 'checkpoint_sha256': before,
'step': step, 'training_source_commit': saved['source_commit'],
'model_provenance': saved['model_provenance'], 'data_signature': saved['data_signature'],
'config': saved['config'], 'prediction_path': str(evidence),
'prediction_sha256': checksum(evidence), 'metrics': metrics,
'correctness_path': str(correctness_path),
'source_evidence_dirs': candidate.get('evidence_dirs', []),
'evidence_sha256': {str(p.relative_to(destination)):checksum(p)
for p in destination.glob('*/*.json')},
'selection_scope': 'Fixed four-fold temperature-crossfit validation macro-family NLL; no reserved calibration/test/holdout predictions read'}
runner.write_json(destination/'verified.json', record)
return record
def recorded_process(pid, expected):
if not pid or not expected:
return False
try:
return Path(f'/proc/{pid}/cmdline').read_bytes().split(b'\0')[:-1] == [v.encode() for v in expected]
except FileNotFoundError:
return False
def stage(campaign, state, name, arguments, deadline):
if runner.STOP or time.time() >= deadline:
raise RuntimeError('Stop/deadline reached before ' + name)
code = runner.child_stage(campaign, state, name, arguments, deadline)
if runner.STOP:
raise InterruptedError('Coordinator stop requested')
if code != 0:
raise RuntimeError(f'{name} exited {code}; durable artifacts retained')
def deploy(campaign, state, plan, selected, deadline):
evaluation = campaign/'evaluation'
model = evaluation/'model.pt'
metrics_path = evaluation/'metrics.json'
# A resume may reuse only a completed evaluation of the same frozen selection.
complete = metrics_path.exists() and json.loads(metrics_path.read_text()).get('status') == 'complete'
if complete:
manifest = json.loads((evaluation/'manifest.json').read_text())
if manifest['checkpoint_sha256'] != selected['checkpoint_sha256']:
raise ValueError('Completed evaluation belongs to a different selection')
if manifest.get('data_signature') != selected['data_signature']:
raise ValueError('Completed evaluation data signature differs from selection')
for name in ('experiment.py','training_model.py'):
if manifest.get('source_sha256',{}).get(name) != checksum(ROOT/name):
raise ValueError('Core evaluation source changed since completed evaluation')
else:
if evaluation.exists():
evaluation.rename(campaign/('evaluation_interrupted_' + datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%S%fZ')))
stage(campaign,state,'evaluation',[sys.executable,str(ROOT/'experiment.py'),'finalize',
'--checkpoint',selected['checkpoint'],'--dataset',selected['config']['dataset'],'--output',str(evaluation)],deadline-120)
result = json.loads(metrics_path.read_text())
if result.get('status') != 'complete' or checksum(model) != result.get('model_sha256'):
raise ValueError('Evaluation/model completion or checksum mismatch')
token_args = ['--max-tokens', str(plan.get('inference_max_tokens', 1024))]
stage(campaign,state,'harness_check',[sys.executable,str(ROOT/'jev_harness.py'),'--backend','local',
'--checkpoint',str(model),'--request',str(ROOT/'examples/jev_request.json'),*token_args],deadline-60)
api_command = [sys.executable,str(ROOT/'jev_harness.py'),'--backend','serve','--checkpoint',str(model),
'--port',str(plan.get('port',18081)),*token_args]
with (campaign/'api.log').open('a') as log:
api = subprocess.Popen(api_command,cwd=ROOT,stdin=subprocess.DEVNULL,stdout=log,
stderr=subprocess.STDOUT,start_new_session=True)
state.update(stage='deploying',api_pid=api.pid,api_command=api_command,
url=f'http://127.0.0.1:{plan.get("port",18081)}',api_ready=False)
runner.write_json(campaign/'state.json',state)
try:
ready_deadline = min(deadline, time.time()+60)
while time.time() < ready_deadline and not runner.STOP and api.poll() is None:
state['heartbeat_utc'] = utc()
runner.write_json(campaign/'state.json',state)
try:
headers = {}
if os.environ.get('OPENSYSONE_API_KEY'):
headers['Authorization'] = 'Bearer ' + os.environ['OPENSYSONE_API_KEY']
with urllib.request.urlopen(urllib.request.Request(state['url']+'/health',headers=headers),timeout=3) as response:
health = json.load(response)
if health.get('status') == 'ready' and health.get('checkpoint') == str(model):
state['api_ready'] = True
break
except (OSError,ValueError):
pass
time.sleep(2)
if not state['api_ready']:
raise RuntimeError('Selected-model API failed to become ready before deadline')
if runner.STOP or time.time() >= deadline:
raise InterruptedError('Stop/deadline reached before final API verification')
from jev_harness import validate_response
payload = json.loads((ROOT/'examples/jev_request.json').read_text())
headers['Content-Type'] = 'application/json'
request = urllib.request.Request(state['url']+'/v1/systemone',
data=json.dumps(payload).encode(),headers=headers,method='POST')
with urllib.request.urlopen(request,timeout=min(30,max(0.1,deadline-time.time()))) as response:
api_result = json.load(response)
validate_response(payload,api_result)
runner.write_json(campaign/'api_probe.json',{'request':payload,'response':api_result,
'verified_utc':utc(),'checkpoint_sha256':checksum(model)})
if runner.STOP or time.time() >= deadline:
raise InterruptedError('Stop/deadline reached before publishing deployment')
pointer = {'model':str(model),'sha256':checksum(model),'campaign':str(campaign),
'evaluation':str(metrics_path),'selection':str(campaign/'selection.json'),
'inference_max_tokens':plan.get('inference_max_tokens',1024),
'model_id':health.get('model'),'finalized_utc':utc()}
directory = Path.home()/'ai/opensysone/deploy'
directory.mkdir(parents=True,exist_ok=True)
runner.write_json(directory/'current.json',pointer)
runner.write_json(campaign/'deployment.json',pointer)
state.update(status='complete',stage='serving',model=str(model),finished_utc=utc())
runner.write_json(campaign/'state.json',state)
except BaseException:
if api.poll() is None:
api.terminate()
try:
api.wait(timeout=5)
except subprocess.TimeoutExpired:
api.kill()
api.wait(timeout=5)
raise
def run_locked(campaign):
campaign = Path(campaign).resolve()
plan = json.loads((campaign/'plan.json').read_text())
cutoff, deadline = validate_plan(plan)
runner.STOP = False
runner.CHILD = None
signal.signal(signal.SIGTERM,runner.stop)
signal.signal(signal.SIGINT,runner.stop)
Path('/proc/self/oom_score_adj').write_text('0')
state = {'campaign':str(campaign),'supervisor_pid':os.getpid(),
'supervisor_command':[sys.executable,str(Path(__file__).resolve()),'--campaign',str(campaign),'--run'],
'status':'running','stage':'waiting_for_selection','started_utc':utc(),
'source_commit':subprocess.check_output(['git','rev-parse','HEAD'],cwd=ROOT,text=True).strip(),
'source_sha256':checksum(Path(__file__))}
runner.write_json(campaign/'state.json',state)
try:
selection_path = campaign/'selection.json'
if not selection_path.exists():
while time.time() < cutoff and not runner.STOP:
state['heartbeat_utc'] = utc()
runner.write_json(campaign/'state.json',state)
time.sleep(min(5,max(0.01,cutoff-time.time())))
if runner.STOP:
raise InterruptedError('Coordinator stopped; independently bounded candidate jobs remain recorded in plan')
state.update(stage='stopping_candidates',candidates={})
runner.write_json(campaign/'state.json',state)
# Stop all reachable jobs before snapshotting. Unreachable remote jobs
# are excluded; an unverified local job must block GPU finalization.
stopped = []
for candidate in plan['candidates']:
if runner.STOP:
raise InterruptedError('Coordinator stopped during candidate shutdown')
try:
report = stop_candidate(candidate)
state['candidates'][candidate['name']] = {'stop_status':report}
stopped.append(candidate)
except Exception as error:
state['candidates'][candidate['name']] = {'eligible':False,'error':str(error)}
if candidate.get('host','local') == 'local':
raise RuntimeError('Cannot establish that GX10 candidate stopped') from error
runner.write_json(campaign/'state.json',state)
if plan.get('reference_sha256') and checksum(plan['reference_predictions']) != plan['reference_sha256']:
raise ValueError('Reference validation changed while awaiting selection')
reference = json.loads(Path(plan['reference_predictions']).read_text())
rows = [{'name':name,**record} for name,record in state['candidates'].items()
if record.get('eligible') is False]
attempt = campaign/('selection_attempt_' + datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%S%fZ'))
attempt.mkdir()
for candidate in stopped:
if runner.STOP:
raise InterruptedError('Coordinator stopped during candidate snapshots')
try:
row = snapshot_candidate(candidate,attempt/candidate['name'],reference)
dataset_proof = verify_candidate_dataset(candidate, plan, row['config']['dataset'])
if dataset_proof is not None:
row['dataset_compatibility'] = dataset_proof
except Exception as error:
row = {'name':candidate['name'],'eligible':False,'error':str(error)}
rows.append(row)
runner.write_json(attempt/'candidates.json',rows)
state['heartbeat_utc'] = utc()
runner.write_json(campaign/'state.json',state)
selected = choose_candidate(rows)
if runner.STOP:
raise InterruptedError('Coordinator stopped before freezing selection')
runner.write_json(selection_path,{'selected':selected,'candidates':rows,'selected_utc':utc(),
'reference_sha256':checksum(plan['reference_predictions'])})
else:
selected = json.loads(selection_path.read_text())['selected']
if checksum(selected['checkpoint']) != selected['checkpoint_sha256']:
raise ValueError('Frozen selection checkpoint changed')
# Also recheck the explicit registration/protected bytes when resuming a
# frozen selection. Full artifact/data signatures were checked at snapshot.
verify_selected_dataset(selected, plan)
if runner.STOP:
raise InterruptedError('Coordinator stop requested')
state.update(stage='acquiring_gx10_lock',selected=selected['name'])
runner.write_json(campaign/'state.json',state)
with (RUN_ROOT/'.smoke.lock').open('a') as lock:
fcntl.flock(lock,fcntl.LOCK_EX | fcntl.LOCK_NB)
deploy(campaign,state,plan,selected,deadline)
return 0
except Exception as error:
state.update(status='interrupted' if runner.STOP else 'failed',error=str(error),finished_utc=utc())
runner.write_json(campaign/'state.json',state)
print(json.dumps(state),flush=True)
return 1
def run(campaign):
RUN_ROOT.mkdir(parents=True,exist_ok=True)
with (RUN_ROOT/'.fleet.lock').open('a') as lock:
try:
fcntl.flock(lock,fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
print('Another fleet coordinator holds .fleet.lock',file=sys.stderr,flush=True)
return 1
try:
return run_locked(campaign)
except Exception as error:
state = {'campaign':str(Path(campaign).resolve()),'supervisor_pid':os.getpid(),
'status':'failed','stage':'startup','error':str(error),'finished_utc':utc()}
runner.write_json(Path(campaign)/'state.json',state)
print(json.dumps(state),flush=True)
return 1
def inspect(campaign, stop=False):
state = json.loads((campaign/'state.json').read_text())
flags = {key:recorded_process(state.get(key+'_pid'),state.get(key+'_command'))
for key in ('supervisor','child','api')}
if stop:
for key in ('supervisor','child','api'):
if flags[key]:
os.kill(state[key+'_pid'],signal.SIGTERM)
break
else:
raise RuntimeError('No exact command-verified fleet process remains')
print(json.dumps({'state':state,'running':flags},indent=2))
return flags
def detach(campaign):
environment = os.environ.copy()
environment.update(PYTHONUNBUFFERED='1',TOKENIZERS_PARALLELISM='false',HF_HUB_DISABLE_XET='1',
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True')
with (campaign/'supervisor.log').open('a') as log:
process = subprocess.Popen([sys.executable,str(Path(__file__).resolve()),'--campaign',str(campaign),'--run'],
cwd=ROOT,stdin=subprocess.DEVNULL,stdout=log,stderr=subprocess.STDOUT,env=environment,start_new_session=True)
(RUN_ROOT/'LAST_FLEET_CAMPAIGN').write_text(str(campaign)+'\n')
print(json.dumps({'campaign':str(campaign),'supervisor_pid':process.pid}))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--plan')
parser.add_argument('--campaign')
parser.add_argument('--run',action='store_true',help=argparse.SUPPRESS)
parser.add_argument('--status',action='store_true')
parser.add_argument('--stop',action='store_true')
parser.add_argument('--resume',action='store_true')
args = parser.parse_args()
if args.plan:
if args.campaign or args.run or args.status or args.stop or args.resume:
parser.error('--plan cannot be combined with campaign control')
plan = json.loads(Path(args.plan).read_text())
plan.setdefault('reference_sha256',checksum(plan['reference_predictions']))
validate_plan(plan)
campaign = RUN_ROOT/(datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%S%fZ')+'-fleet')
campaign.mkdir(parents=True,exist_ok=False)
runner.write_json(campaign/'plan.json',plan)
detach(campaign)
else:
if not args.campaign:
parser.error('--plan or --campaign is required')
campaign = Path(args.campaign).resolve()
if args.run:
code = run(campaign)
(campaign/'exit_code').write_text(str(code)+'\n')
raise SystemExit(code)
if args.resume:
validate_plan(json.loads((campaign/'plan.json').read_text()))
flags = inspect(campaign)
if any(flags.values()):
raise RuntimeError('Stop existing recorded fleet processes before resume')
detach(campaign)
else:
inspect(campaign,stop=args.stop)
if __name__ == '__main__':
main()