match_runner.py
python · 359 lines · Sanitized derivative
Sanitized derivative: private paths or personal test identities use explicit placeholders. Original line count is preserved.
Version & provenance · foundation-20261029
Recorded SHA-256 8d12cb05d94132ccec06fa63bf2c2c415be8f97a87d87b18db134650e398c011Rendered SHA-256 0b9aee9ac71cc068cd8a6e5e533bfc4d2113749f699565e796b11ad0ba522adf
Original project code: Apache-2.0. Dependency licenses remain separate. License notes. Line links are stable within this snapshot. Allowlisted foundation training and frozen evaluation source; recorded hashes refer to original files, rendered hashes identify any path-redacted derivatives. This subset is not a standalone training distribution; no host configs, credentials, optimizer state or dataset bulk included.
1"""Frozen-suite runner. Default is plan-only; matches require a reviewed release.
2
3Existing model/harness/serving files are read-only. Linux guardian owns the match
4worker/model group; detached UCI children additionally die with their parent.
5"""
6import argparse,ctypes,hashlib,importlib.util,io,json,math,os,re,signal,subprocess,sys,time,uuid
7from pathlib import Path
8
9def engine_child(parent,command):
10 """Contain the engine before importing project packages or executing it."""
11 if os.name!='posix':raise RuntimeError('Linux parent-death handling required')
12 if ctypes.CDLL(None,use_errno=True).prctl(1,signal.SIGKILL,0,0,0)!=0:raise OSError(ctypes.get_errno(),'PDEATHSIG failed')
13 if os.getppid()!=parent:raise RuntimeError('engine parent disappeared before initialization')
14 os.execv(command[0],command)
15
16if __name__=='__main__' and sys.argv[1:2]==['--engine-child']:
17 engine_child(int(sys.argv[2]),sys.argv[3:])
18
19ROOT=Path(__file__).resolve().parent
20PROJECT=ROOT.parents[1]
21HARNESS_ROOT=PROJECT.parent.parent/'task-16'
22GUARDIAN_PATH=(ROOT.parent/'runtime/training_deadline.py').resolve()
23MODEL_METRICS={'raw_greedy_tokens','raw_greedy_legal','legal_joint_probability',
24 'illegal_or_nonmove_three_token_probability','selected_joint_log_probability','forward_calls'}
25APPROVAL_KEYS={'approved','run_id','run_directory','suite_sha256','execution_contract_sha256','runner_sha256','guardian_sha256','checkpoint','checkpoint_sha256','dataset_manifest','dataset_manifest_sha256','device','role','budget_seconds'}
26sys.path[:0]=[str(PROJECT),str(HARNESS_ROOT),str(ROOT.parent/'runtime')]
27# Make only the existing pure-Python chess package visible in spawned model workers.
28if importlib.util.find_spec('chess') is None:
29 package=Path('/PUBLIC_PLACEHOLDER/install-python-chess')
30 spec=importlib.util.spec_from_file_location('chess',package/'__init__.py',submodule_search_locations=[str(package)])
31 module=importlib.util.module_from_spec(spec);sys.modules['chess']=module;spec.loader.exec_module(module)
32
33def sha(path):
34 h=hashlib.sha256()
35 with Path(path).open('rb') as stream:
36 while block:=stream.read(8*1024*1024):h.update(block)
37 return h.hexdigest()
38
39def load_guardian(expected_hash=None):
40 """Load exactly the approved file, independent of sys.path/sys.modules."""
41 path=GUARDIAN_PATH.resolve()
42 source=path.read_bytes()
43 if expected_hash is not None and hashlib.sha256(source).hexdigest()!=expected_hash:raise ValueError('approved guardian changed')
44 spec=importlib.util.spec_from_file_location('_chess_match_guardian_'+uuid.uuid4().hex,path)
45 module=importlib.util.module_from_spec(spec);exec(compile(source,str(path),'exec'),module.__dict__)
46 if Path(module.__file__).resolve()!=path:raise RuntimeError('guardian module identity mismatch')
47 return module
48
49def require_guardian():
50 if os.environ.get('CHESS_MATCH_GUARDED')!='1' or os.getpgrp()!=os.getpid():raise RuntimeError('match worker requires its guardian-owned process group')
51 parent_command=Path(f'/proc/{os.getppid()}/cmdline').read_bytes().split(b'\0')
52 if str(GUARDIAN_PATH).encode() not in parent_command or b'--guardian' not in parent_command:
53 raise RuntimeError('match worker parent is not the approved guardian')
54
55def model_metrics(row,board):
56 """Raw model rows cannot evade denominators or omit probability diagnostics."""
57 import chess
58 if row.get('model_query')!='queried' or not MODEL_METRICS.issubset(row):raise ValueError('model policy requires queried and complete raw metrics')
59 raw=row['raw_greedy_tokens']
60 if not isinstance(raw,list) or len(raw)!=3 or any(type(t)is not int or not 0<=t<128 for t in raw):raise ValueError('invalid raw greedy tokens')
61 if type(row['raw_greedy_legal'])is not bool:raise ValueError('invalid raw legality flag')
62 promotions={None:64,chess.KNIGHT:65,chess.BISHOP:66,chess.ROOK:67,chess.QUEEN:68}
63 legal=any(raw==[m.from_square,m.to_square,promotions[m.promotion]] for m in board.legal_moves)
64 if row['raw_greedy_legal']!=legal:raise ValueError('raw greedy legality disagrees with board')
65 for key in ('legal_joint_probability','illegal_or_nonmove_three_token_probability','selected_joint_log_probability'):
66 if type(row[key])not in (int,float) or not math.isfinite(row[key]):raise ValueError('invalid raw model metrics')
67 mass=row['legal_joint_probability'];illegal=row['illegal_or_nonmove_three_token_probability']
68 if not 0<=mass<=1+1e-8 or not 0<=illegal<=1+1e-8 or abs(illegal-max(0.,1.-mass))>1e-8:raise ValueError('invalid probability mass accounting')
69 if row['selected_joint_log_probability']>1e-8:raise ValueError('invalid selected log probability')
70 if type(row['forward_calls'])is not int or row['forward_calls']<1:raise ValueError('invalid forward-call count')
71def write(path,value):
72 path=Path(path);tmp=path.with_name(path.name+'.tmp')
73 with tmp.open('w',encoding='utf-8') as stream:
74 stream.write(value if isinstance(value,str) else json.dumps(value,indent=2));stream.flush();os.fsync(stream.fileno())
75 tmp.replace(path)
76def inputs():
77 freeze=json.loads((ROOT/'frozen-v1/freeze.json').read_text())
78 contract=json.loads((ROOT/'execution-contract.json').read_text())
79 if sha(ROOT/'frozen-v1/suite.json')!=freeze['suite_sha256'] or contract['suite_sha256']!=freeze['suite_sha256']:
80 raise ValueError('frozen suite hash mismatch')
81 suite=json.loads((ROOT/'frozen-v1/suite.json').read_text(encoding='utf-8'))
82 return suite,contract
83def verify_sources(contract):
84 for name,expected in contract['source_hashes'].items():
85 base=HARNESS_ROOT if name in ('harness.py','mate_override.py') or name.startswith('sunfish/') else PROJECT
86 if sha(base/name)!=expected:raise ValueError('execution source changed: '+name)
87 git=['git','-c','core.autocrlf=true','-c','core.filemode=false','-C',str(HARNESS_ROOT/'sunfish')]
88 if subprocess.check_output(git+['rev-parse','HEAD'],text=True).strip()!=contract['sunfish_commit']:
89 raise ValueError('Sunfish commit changed')
90 if subprocess.check_output(git+['status','--porcelain'],text=True).strip():raise ValueError('Sunfish checkout modified')
91
92def proof_check(h,board,proof,color,depth=0):
93 import chess
94 if depth>3 or board.fen()!=proof['fen']:raise ValueError('bad mate proof state')
95 if proof['kind']=='checkmate':
96 if not board.is_checkmate() or board.turn==color:raise ValueError('false mate proof')
97 return
98 if depth>=3 or h.outcome(board) is not None:raise ValueError('mate proof crosses end/depth')
99 branches=proof['branches']
100 if board.turn!=color:
101 if [x['move'] for x in branches]!=sorted(m.uci() for m in board.legal_moves):raise ValueError('missing defender proof branch')
102 elif len(branches)!=1:raise ValueError('invalid attacker proof branch')
103 for branch in branches:
104 move=chess.Move.from_uci(branch['move'])
105 if move not in board.legal_moves:raise ValueError('illegal proof move')
106 board.push(move)
107 try:proof_check(h,board,branch['child'],color,depth+1)
108 finally:board.pop()
109
110def audit(h,folder,report,opening,color):
111 import chess,chess.pgn
112 with (folder/'game.pgn').open(encoding='utf-8') as stream:game=chess.pgn.read_game(stream)
113 if game is None or game.errors:raise ValueError('invalid played PGN')
114 moves=list(game.mainline_moves());n=opening['autoplay_plies']
115 if [m.uci() for m in moves[:n]]!=opening['uci'] or len(moves)!=report['plies']:raise ValueError('autoplay/ply count mismatch')
116 rows=report['moves'];by_ply={r['ply']:r for r in rows}
117 if len(by_ply)!=len(rows) or set(by_ply)!=set(range(n+1,len(moves)+1)):raise ValueError('book moves included in metrics or missing played moves')
118 board=chess.Board();queried=[];overrides=0;model_turn_seconds=0.
119 for ply,move in enumerate(moves,1):
120 if move not in board.legal_moves:raise ValueError('illegal played move')
121 row=by_ply.get(ply)
122 if row:
123 if row['uci']!=move.uci():raise ValueError('move report mismatch')
124 if board.turn==color and row.get('decision_source') not in ('model_policy','forced_mate_override'):raise ValueError('missing model attribution')
125 if board.turn!=color and ('model_query' in row or 'decision_source' in row or MODEL_METRICS.intersection(row)):raise ValueError('engine attributed to model')
126 if not math.isfinite(row['seconds']) or row['seconds']<0:raise ValueError('invalid move latency')
127 if board.turn==color:model_turn_seconds+=row['seconds']
128 if row.get('decision_source')=='model_policy':
129 model_metrics(row,board)
130 queried.append(row)
131 if row.get('decision_source')=='forced_mate_override':
132 if board.turn!=color or row.get('model_query')!='not_queried' or MODEL_METRICS.intersection(row):raise ValueError('helper/model attribution mismatch')
133 search=row.get('mate_search',{});proof=search.get('proof',{});branches=proof.get('branches',[])
134 if search.get('status')!='proven' or search.get('move')!=move.uci():raise ValueError('helper move/status mismatch')
135 if not isinstance(branches,list) or len(branches)!=1 or branches[0].get('move')!=move.uci():raise ValueError('helper proof root differs from played move')
136 proof_check(h,board,proof,color);overrides+=1
137 board.push(move)
138 if board.fen()!=report['final_fen'] or game.headers['Result']!=report['result']:raise ValueError('final board/result mismatch')
139 outcome=board.outcome(claim_draw=True)
140 if report['result']!='*' and (outcome is None or outcome.result()!=report['result']):raise ValueError('fabricated scored result')
141 nodes=[];path=folder/'uci.log'
142 if path.exists():
143 for block in path.read_text().split('> go nodes 1000')[1:]:
144 observed=re.findall(r' nodes (\d+)',block);nodes.append(int(observed[-1]) if observed else None)
145 game.headers.update(OpeningID=opening['opening_id'],AutoplayPlies=str(n),SourceOpeningName=opening['name'])
146 node=game
147 for _ in range(n):node=node.variation(0);node.comment='Book autoplay; excluded from model metrics.'
148 return game,{'plies':len(moves),'autoplay_plies':n,'model_queries':len(queried),
149 'raw_greedy_legal':sum(r['raw_greedy_legal'] for r in queried),'raw_legal_probability_sum':sum(r['legal_joint_probability'] for r in queried),
150 'helper_overrides':overrides,'sunfish_reported_nodes':nodes,'result':report['result'],
151 'model_turn_seconds':model_turn_seconds,'latency_protocol':'model turns include helper attempt and decode; excludes book autoplay and model loading',
152 'termination':report['termination'],'error':report['error'],'cleanup_error':report['cleanup_error'],
153 'seconds':report['seconds'],'pgn_and_proofs_verified':True}
154
155def summarize(rows,total=100):
156 scored=[r for r in rows if r['result']!='*'];wins=draws=losses=0
157 for row in scored:
158 if row['result']=='1/2-1/2':draws+=1
159 elif row['result']==('1-0' if row['model_color']=='white' else '0-1'):wins+=1
160 else:losses+=1
161 paired={}
162 for row in rows:paired.setdefault(row['pair_id'],[]).append(row)
163 scores=[]
164 for pair in paired.values():
165 if len(pair)==2 and all(r['result']!='*' for r in pair):
166 scores.append(sum(.5 if r['result']=='1/2-1/2' else float(r['result']==('1-0' if r['model_color']=='white' else '0-1')) for r in pair)/2)
167 import statistics
168 return {'scheduled_games':total,'audited_games':len(rows),'unattempted_or_unaudited':total-len(rows),
169 'wins':wins,'draws':draws,'losses':losses,'unfinished':len(rows)-len(scored),
170 'score_on_scored_games':(wins+.5*draws)/len(scored) if scored else None,
171 'fully_scored_pairs':len(scores),'pair_mean_score':statistics.mean(scores) if scores else None,
172 'pair_standard_error':statistics.stdev(scores)/math.sqrt(len(scores)) if len(scores)>1 else None,
173 'uncertainty_limit':'paired-opening standard error; small selected suite, not an Elo/generalization estimate',
174 'model_queries':sum(r['model_queries'] for r in rows),'helper_overrides':sum(r['helper_overrides'] for r in rows),
175 'autoplay_excluded_from_model_metrics':True}
176
177def play(suite,out,checkpoint,h,clock,model_factory=None):
178 """Dependency-injected for offline scheduler/audit/cleanup tests."""
179 p=suite['protocol'];openings={o['opening_id']:o for o in suite['openings']};rows=[];games=[]
180 factory=model_factory or h.ModelWorker
181 write(out/'summary.json',summarize(rows,len(suite['schedule'])))
182 for item in suite['schedule']:
183 if clock.soft_stop():break
184 opening=openings[item['opening_id']];folder=out/item['game_id'];model=None
185 try:
186 timeout=min(p['model_timeout_seconds'],clock.remaining()-5)
187 if timeout<=0:break
188 load_started=time.monotonic();model=factory('training_adapter:load',checkpoint,item['seed'],timeout)
189 load_seconds=time.monotonic()-load_started
190 remaining=clock.remaining()-5
191 if remaining<=0:break
192 game_budget=min(p['game_walltime_seconds'],remaining)
193 game_end=time.monotonic()+game_budget
194 def engine():
195 available=min(clock.remaining()-5,game_end-time.monotonic())
196 if available<=0:raise TimeoutError('no time for engine initialization')
197 # UCI constructor performs two handshakes before the first search.
198 timeout=min(p['engine_timeout_seconds'],available/2)
199 command=[sys.executable,str(Path(__file__).resolve()),'--engine-child',str(os.getpid()),*h.engine_command()]
200 return h.UCI(command,timeout)
201 report=h.game(model,engine,item['model_color']=='white',folder,
202 cap=p['ply_cap_including_autoplay'],nodes=p['sunfish_requested_nodes'],opening=opening['uci'],
203 walltime=game_budget,label='Frozen paired100; no Elo claim',
204 mate_override=True,mate_nodes=p['helper_nodes'],mate_seconds=p['helper_seconds'])
205 game,row=audit(h,folder,report,opening,item['model_color']=='white')
206 row.update(item);row['model_load_seconds']=load_seconds;rows.append(row);games.append(str(game))
207 write(folder/'game.pgn',str(game)+'\n')
208 row['pgn_sha256']=sha(folder/'game.pgn');row['game_json_sha256']=sha(folder/'game.json')
209 write(folder/'audit.json',row)
210 write(out/'results.json',rows);write(out/'summary.json',summarize(rows,len(suite['schedule'])))
211 write(out/'games.pgn','\n\n'.join(games)+'\n')
212 if report['cleanup_error'] or report['error']:break # No hidden retry/new budget.
213 finally:
214 if model is not None:model.close()
215 write(out/'summary.json',summarize(rows,len(suite['schedule'])))
216 return rows
217
218def compare(baseline,candidate,baseline_rows,candidate_rows,suite):
219 """Paired comparison only after checking identical evaluation conditions."""
220 import statistics
221 if baseline['request']['role']!='baseline' or candidate['request']['role']!='candidate':raise ValueError('comparison roles mismatch')
222 keys=('suite_sha256','execution_contract_sha256','runner_sha256','guardian_sha256','device','budget_seconds')
223 if any(baseline['request'][k]!=candidate['request'][k] for k in keys):raise ValueError('matched execution identity differs')
224 if any(baseline[k]!=candidate[k] for k in ('protocol','model_config','python','torch','transformers','python_chess')):raise ValueError('matched protocol/runtime differs')
225 if baseline['request']['suite_sha256']!=inputs()[1]['suite_sha256']:raise ValueError('comparison uses another suite')
226 if baseline['request']['checkpoint_sha256']!=suite['protocol']['baseline_checkpoint_sha256']:raise ValueError('wrong comparison baseline')
227 schedule={g['game_id']:g for g in suite['schedule']}
228 mapped=[]
229 for rows in (baseline_rows,candidate_rows):
230 table={r['game_id']:r for r in rows}
231 if len(table)!=len(rows) or set(table)!=set(schedule):raise ValueError('comparison requires all100 scheduled audits')
232 for key,row in table.items():
233 if any(row[k]!=schedule[key][k] for k in ('opening_id','model_color','seed','pair_id')) or row.get('pgn_and_proofs_verified') is not True:raise ValueError('comparison schedule/audit mismatch')
234 mapped.append(table)
235 complete=all(r['result']!='*' and not r['error'] and not r['cleanup_error'] for rows in mapped for r in rows.values())
236 result={'identical_protocol_verified':True,'all_games_scored_without_errors':complete,
237 'baseline':summarize(baseline_rows),'candidate':summarize(candidate_rows),'promotion_authorized':False}
238 if not complete:
239 return dict(result,comparison_status='incomplete; no improvement conclusion',evidence_for_improvement=False)
240 def score(row):return .5 if row['result']=='1/2-1/2' else float(row['result']==('1-0' if row['model_color']=='white' else '0-1'))
241 differences=[]
242 for opening in suite['openings']:
243 ids=[g['game_id'] for g in suite['schedule'] if g['opening_id']==opening['opening_id']]
244 differences.append(sum(score(mapped[1][key])-score(mapped[0][key]) for key in ids)/2)
245 mean=statistics.mean(differences);se=statistics.stdev(differences)/math.sqrt(len(differences))
246 interval=[mean-1.96*se,mean+1.96*se]
247 return dict(result,comparison_status='matched',candidate_minus_baseline_score=mean,
248 opening_pair_standard_error=se,approximate_95_percent_interval=interval,
249 evidence_for_improvement=interval[0]>0,
250 uncertainty_limit='normal approximation over50 opening pairs; selected suite, not an Elo estimate; independent review required')
251
252def compare_directories(baseline_path,candidate_path):
253 suite,contract=inputs();verify_sources(contract)
254 import harness as h
255 openings={o['opening_id']:o for o in suite['openings']};manifests=[];results=[]
256 for root in map(Path,(baseline_path,candidate_path)):
257 manifest=json.loads((root/'manifest.json').read_text());manifests.append(manifest)
258 expected={'execution_contract_sha256':sha(ROOT/'execution-contract.json'),'runner_sha256':sha(__file__),
259 'guardian_sha256':sha(GUARDIAN_PATH),'suite_sha256':contract['suite_sha256']}
260 if any(manifest['request'][k]!=v for k,v in expected.items()) or manifest['protocol']!=suite['protocol']:raise ValueError('comparison source contract changed')
261 rows=json.loads((root/'results.json').read_text())
262 for row in rows:
263 folder=(root/row['game_id']).resolve()
264 if folder.parent!=root.resolve():raise ValueError('unsafe game artifact path')
265 if sha(folder/'game.pgn')!=row['pgn_sha256'] or sha(folder/'game.json')!=row['game_json_sha256']:raise ValueError('played artifacts changed')
266 report=json.loads((folder/'game.json').read_text())
267 _,checked=audit(h,folder,report,openings[row['opening_id']],row['model_color']=='white')
268 if any(row[key]!=checked[key] for key in ('result','termination','error','cleanup_error','plies','autoplay_plies','model_queries','helper_overrides','raw_greedy_legal','raw_legal_probability_sum')):
269 raise ValueError('stored result differs from replayed game audit')
270 results.append(rows)
271 return compare(*manifests,*results,suite)
272
273def worker(request_path):
274 # The private entry point must not bypass the external hard watchdog.
275 require_guardian()
276 request=json.loads(Path(request_path).read_text());out=Path(request_path).parent
277 guardian=load_guardian(request.get('guardian_sha256'))
278 value=guardian.read_deadline(out/'deadline.json')
279 if (set(request)!=APPROVAL_KEYS or value['identity']!=request or request.get('approved') is not True
280 or request['budget_seconds']!=7200 or value['budget_seconds']!=7200 or value['checkpoint_margin_seconds']!=30):raise ValueError('worker request/deadline mismatch')
281 if str(uuid.UUID(request['run_id']))!=request['run_id']:raise ValueError('invalid worker run UUID')
282 if out.resolve()!=(ROOT/'runs'/request['run_id']).resolve() or str(out.resolve())!=request['run_directory']:raise ValueError('noncanonical worker run directory')
283 clock=guardian.Deadline(value)
284 if clock.soft_stop():raise TimeoutError('evaluation budget expired before setup')
285 suite,contract=inputs();verify_sources(contract)
286 if request['suite_sha256']!=contract['suite_sha256'] or request['runner_sha256']!=sha(__file__) or request['execution_contract_sha256']!=sha(ROOT/'execution-contract.json') or request['guardian_sha256']!=sha(GUARDIAN_PATH):
287 raise ValueError('worker approved source changed')
288 if request['device'] not in ('cuda:0','cuda:1') or request['role'] not in ('baseline','candidate'):raise ValueError('invalid worker role/device')
289 if request['role']=='baseline' and request['checkpoint_sha256']!=suite['protocol']['baseline_checkpoint_sha256']:raise ValueError('wrong worker baseline')
290 if sha(request['checkpoint'])!=request['checkpoint_sha256'] or sha(request['dataset_manifest'])!=request['dataset_manifest_sha256']:raise ValueError('checkpoint/dataset changed')
291 # Single attempt even when the private worker entry point is invoked twice.
292 with (out/'worker-started.json').open('x') as marker:
293 json.dump({'pid':os.getpid(),'started_unix':time.time(),'request_sha256':sha(request_path)},marker);marker.flush();os.fsync(marker.fileno())
294 import training_core as tc
295 import torch,transformers,chess
296 saved=tc.load_checkpoint(request['checkpoint'])
297 cfg=saved['model_config'];expected={'n_layer':12,'n_embd':768,'n_head':12,'vocab_size':128,'n_positions':1024,'n_ctx':1024}
298 if any(cfg.get(k)!=v for k,v in expected.items()) or saved['identity'].get('parameters')!=85940736:raise ValueError('baseline architecture mismatch')
299 dataset=json.loads(Path(request['dataset_manifest']).read_text())
300 if saved['identity']['dataset_fingerprint']!=dataset['fingerprint']:raise ValueError('checkpoint dataset mismatch')
301 write(out/'manifest.json',{'request':request,'protocol':suite['protocol'],'model_config':cfg,
302 'checkpoint_identity':saved['identity'],'checkpoint_cursor':saved['cursor'],
303 'python':sys.version,'torch':str(torch.__version__),'transformers':transformers.__version__,
304 'python_chess':chess.__version__,'model_reload_each_game':True,'test_set_evaluated':False})
305 del saved
306 import harness as h
307 os.environ['CHESS_INFERENCE_DEVICE']=request['device']
308 try:
309 rows=play(suite,out,Path(request['checkpoint']),h,clock)
310 write(out/'terminal.json',{'status':'all_scheduled_audited' if len(rows)==100 else 'partial','audited_games':len(rows),'test_set_evaluated':False})
311 except BaseException as error:
312 write(out/'failure.json',{'error':repr(error)});raise
313
314def launch(approval_path):
315 import fcntl
316 suite,contract=inputs();approval=json.loads(Path(approval_path).read_text());run_id=approval.get('run_id')
317 if str(uuid.UUID(run_id))!=run_id:raise ValueError('canonical run UUID required')
318 if set(approval)!=APPROVAL_KEYS or approval['approved'] is not True or approval['budget_seconds']!=7200:raise ValueError('exact reviewed match approval required')
319 if approval['suite_sha256']!=contract['suite_sha256'] or approval['execution_contract_sha256']!=sha(ROOT/'execution-contract.json') or approval['runner_sha256']!=sha(__file__):raise ValueError('approved source/suite mismatch')
320 guardian=load_guardian(approval['guardian_sha256'])
321 if approval['device'] not in ('cuda:0','cuda:1') or approval['role'] not in ('baseline','candidate'):raise ValueError('invalid reviewed device/role')
322 if approval['role']=='baseline' and approval['checkpoint_sha256']!=suite['protocol']['baseline_checkpoint_sha256']:raise ValueError('incorrect baseline checkpoint')
323 for key in ('checkpoint','dataset_manifest'):
324 if str(Path(approval[key]).resolve())!=approval[key] or not Path(approval[key]).is_file():raise ValueError('canonical existing input required')
325 out=(ROOT/'runs'/run_id).resolve();out.parent.mkdir(exist_ok=True)
326 if approval['run_directory']!=str(out):raise ValueError('alternate run directory forbidden')
327 # Fresh UUID directory only; no replay/resume/reset of an earlier match budget.
328 out.mkdir(exist_ok=False)
329 with (out/'owner.lock').open('x') as lock:
330 fcntl.flock(lock,fcntl.LOCK_EX|fcntl.LOCK_NB)
331 value=guardian.create_or_resume(out/'deadline.json',approval,budget=7200,margin=30)
332 write(out/'request.json',approval)
333 env=dict(os.environ,CHESS_JOB_LOCK_FD=str(lock.fileno()),CHESS_MATCH_GUARDED='1')
334 command=[sys.executable,str(Path(__file__).resolve()),'--worker',str(out/'request.json')]
335 result=guardian.supervise(command,value,env);write(out/'supervision.json',result)
336 return result
337
338def main():
339 if sys.argv[1:2]==['--engine-child']:
340 return engine_child(int(sys.argv[2]),sys.argv[3:])
341 if sys.argv[1:2]==['--worker']:
342 path=Path(sys.argv[2]).resolve()
343 if path.name!='request.json' or path.parent.parent!=(ROOT/'runs').resolve():raise ValueError('private worker path outside run registry')
344 with (path.parent/'worker.log').open('a',buffering=1) as log:
345 os.dup2(log.fileno(),1);os.dup2(log.fileno(),2)
346 return worker(path)
347 parser=argparse.ArgumentParser();parser.add_argument('--approval');parser.add_argument('--authorize-matches',action='store_true')
348 parser.add_argument('--compare',nargs=2,metavar=('BASELINE','CANDIDATE'))
349 args=parser.parse_args()
350 if args.compare:
351 if args.authorize_matches or args.approval:parser.error('comparison is read-only and cannot launch')
352 print(json.dumps(compare_directories(*args.compare),indent=2));return
353 if not args.authorize_matches:
354 suite,contract=inputs();print(json.dumps({'status':'plan_only','games_per_checkpoint':len(suite['schedule']),'suite_sha256':contract['suite_sha256'],'runner_sha256':sha(__file__),'matches_run':0}));return
355 if not args.approval:parser.error('reviewed approval file required')
356 result=launch(args.approval)
357 if result['returncode'] or result['deadline_expired']:raise SystemExit(result['returncode'] or 124)
358if __name__=='__main__':main()
359