Dhruv1000 commited on
Commit
df7014f
·
verified ·
1 Parent(s): 26bb624

Organize complete research documentation and recovery inventory

Browse files
scripts/run_review26_e4b_supervisor.py CHANGED
@@ -5,6 +5,11 @@ from datetime import datetime, timezone
5
  from pathlib import Path
6
 
7
  ROOT=Path(__file__).resolve().parents[1]
 
 
 
 
 
8
  DEFAULT_RUN=ROOT/'results/phase6/review26/e4b_balanced_reward'
9
 
10
  def utc(): return datetime.now(timezone.utc).isoformat()
@@ -108,18 +113,49 @@ def start_pending_archive(run_dir,state,log,popen=subprocess.Popen):
108
  state['archive_worker_pid']=child.pid;state['archive_worker_step']='stop'
109
  _write_log(log,f'started HF stopped-run archive pid={child.pid}')
110
 
111
- def supervise(run_dir, *, poll_seconds=5, free_check=gpu_is_free, popen=subprocess.Popen):
 
112
  run_dir=Path(run_dir).resolve();run_dir.mkdir(parents=True,exist_ok=True)
113
  manifest=json.loads((run_dir/'run_manifest.json').read_text())
114
  if manifest.get('launch_authority')!='D-GRPO-17': raise RuntimeError('wrong launch authority')
115
  state_path=run_dir/'e4b_supervisor_state.json';terminal=run_dir/'e4b_terminal_stop.json'
116
  log=run_dir/'e4b_supervisor.log'
117
- if terminal.exists(): _write_log(log,'terminal marker already exists; refusing launch');return 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  if (run_dir/'e4b_supervisor_tripwire.json').exists():
119
  atomic_json(terminal,dict(status='stopped',disposition='tripwire_terminal',
120
  marker='e4b_supervisor_tripwire.json',at_utc=utc()))
121
  _write_log(log,'persisted tripwire marker found at startup; refusing auto-resume');return 0
122
- state=json.loads(state_path.read_text()) if state_path.exists() else dict(gpu_seconds_used=0.,restarts=0)
123
  abandoned_start=state.pop('active_child_started_at',None)
124
  had_interrupted_child=abandoned_start is not None
125
  if abandoned_start is not None:
@@ -267,8 +303,9 @@ def shutil_disk_fraction(root):
267
 
268
  def main():
269
  ap=argparse.ArgumentParser();ap.add_argument('--run-dir',type=Path,default=DEFAULT_RUN)
 
270
  args=ap.parse_args()
271
- try:return supervise(args.run_dir)
272
  except BaseException as exc:
273
  run_dir=Path(args.run_dir)
274
  try:
 
5
  from pathlib import Path
6
 
7
  ROOT=Path(__file__).resolve().parents[1]
8
+ # systemd invokes this file by absolute path, which puts ``scripts/`` rather
9
+ # than the repository root at sys.path[0]. Runtime helpers use the ``scripts``
10
+ # namespace, so make imports independent of the launch form and working dir.
11
+ if str(ROOT) not in sys.path:
12
+ sys.path.insert(0, str(ROOT))
13
  DEFAULT_RUN=ROOT/'results/phase6/review26/e4b_balanced_reward'
14
 
15
  def utc(): return datetime.now(timezone.utc).isoformat()
 
113
  state['archive_worker_pid']=child.pid;state['archive_worker_step']='stop'
114
  _write_log(log,f'started HF stopped-run archive pid={child.pid}')
115
 
116
+ def supervise(run_dir, *, poll_seconds=5, free_check=gpu_is_free, popen=subprocess.Popen,
117
+ review28_authorized_resume=False):
118
  run_dir=Path(run_dir).resolve();run_dir.mkdir(parents=True,exist_ok=True)
119
  manifest=json.loads((run_dir/'run_manifest.json').read_text())
120
  if manifest.get('launch_authority')!='D-GRPO-17': raise RuntimeError('wrong launch authority')
121
  state_path=run_dir/'e4b_supervisor_state.json';terminal=run_dir/'e4b_terminal_stop.json'
122
  log=run_dir/'e4b_supervisor.log'
123
+ state=json.loads(state_path.read_text()) if state_path.exists() else dict(gpu_seconds_used=0.,restarts=0)
124
+ if terminal.exists():
125
+ if not review28_authorized_resume:
126
+ _write_log(log,'terminal marker already exists; refusing launch');return 0
127
+ try:
128
+ old_terminal=json.loads(terminal.read_text())
129
+ prior_status=old_terminal['worker_status']
130
+ eval_status_path=run_dir/'e4b_step100_eval_worker_status.json'
131
+ eval_status=json.loads(eval_status_path.read_text())
132
+ eval_metrics_path=Path(eval_status['metrics_path'])
133
+ if not eval_metrics_path.is_absolute(): eval_metrics_path=ROOT/eval_metrics_path
134
+ except (OSError,KeyError,ValueError,json.JSONDecodeError):
135
+ _write_log(log,'Review #28 resume refused: missing preserved failure/eval evidence');return 0
136
+ if (old_terminal.get('disposition')!='software_or_runtime_failure_hold' or
137
+ prior_status.get('status')!='failed' or
138
+ 'FileExistsError' not in str(prior_status.get('stop_reason','')) or
139
+ eval_status.get('status')!='eval_only_complete' or
140
+ not eval_metrics_path.is_file() or
141
+ (run_dir/'e4b_supervisor_tripwire.json').exists()):
142
+ _write_log(log,'Review #28 resume refused: failure cause/eval result/tripwire precondition mismatch');return 0
143
+ if not state.get('review28_step100_eval_charged'):
144
+ state['gpu_seconds_used']=float(state.get('gpu_seconds_used',0.))+float(eval_status['gpu_wall_hours'])*3600
145
+ state['review28_step100_eval_charged']=True
146
+ state['review28_eval_gpu_hours']=float(eval_status['gpu_wall_hours'])
147
+ atomic_json(state_path,state)
148
+ eval_status['budget_charged_to_e4b'] = True
149
+ atomic_json(eval_status_path,eval_status)
150
+ for source,name in ((run_dir/'scale_final_status.json','scale_final_status_pre_review28.json'),
151
+ (terminal,'e4b_terminal_stop_pre_review28.json')):
152
+ archived=run_dir/name
153
+ if source.exists() and not archived.exists(): os.replace(source,archived)
154
+ _write_log(log,'Review #28 authorized software-failure recovery: archived prior terminal markers; step-100 eval GPU time charged')
155
  if (run_dir/'e4b_supervisor_tripwire.json').exists():
156
  atomic_json(terminal,dict(status='stopped',disposition='tripwire_terminal',
157
  marker='e4b_supervisor_tripwire.json',at_utc=utc()))
158
  _write_log(log,'persisted tripwire marker found at startup; refusing auto-resume');return 0
 
159
  abandoned_start=state.pop('active_child_started_at',None)
160
  had_interrupted_child=abandoned_start is not None
161
  if abandoned_start is not None:
 
303
 
304
  def main():
305
  ap=argparse.ArgumentParser();ap.add_argument('--run-dir',type=Path,default=DEFAULT_RUN)
306
+ ap.add_argument('--review28-authorized-resume',action='store_true')
307
  args=ap.parse_args()
308
+ try:return supervise(args.run_dir,review28_authorized_resume=args.review28_authorized_resume)
309
  except BaseException as exc:
310
  run_dir=Path(args.run_dir)
311
  try:
scripts/run_scale_grpo.py CHANGED
@@ -39,6 +39,33 @@ def select_rollout(provenance):
39
  return int.from_bytes(hashlib.sha256(key.encode()).digest()[:8], 'big') % 20 == 0
40
 
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  class ScaleRuntime(Runtime):
43
  sample_weight_fn=staticmethod(bounded_zero_correct_sample_difficulty_weight)
44
 
@@ -151,7 +178,6 @@ class ScaleRuntime(Runtime):
151
  ids=[r['prompt_id'] for r in self.manifest['valid_selection']]
152
  labels={r['prompt_id']:int(r['target']) for r in self.manifest['valid_selection']}
153
  prompts=[self.rows[pid]['prompt'] for pid in ids]
154
- self.trainer._move_model_to_vllm()
155
  sampled=self.trainer.llm.generate(prompts,sampling_params=SamplingParams(
156
  temperature=.8,max_tokens=1536,n=8,seed=42),use_tqdm=True)
157
  records=[];correct_vuln_r2=[]
@@ -198,6 +224,7 @@ class ScaleRuntime(Runtime):
198
  if len(self.eval_entropies)>=2 and all(x<.3 for x in self.eval_entropies[-2:]):
199
  raise SmokeStop('two_consecutive_VALID_entropies_below_0.3 [D-GRPO-9]')
200
  metrics=dict(optimizer_step=step,checkpoint=str(checkpoint),adapter_label='E4 balanced reward',
 
201
  inference_protocol='E2 exact: 8 generations, temperature 0.8, max_tokens 1536, seed 42',
202
  n_rows=len(records),n_pairs=len({r['pair_id'] for r in records}),
203
  parse_rate=sampled_parse,row_auc=score['auc'],
@@ -206,6 +233,7 @@ class ScaleRuntime(Runtime):
206
  greedy_label_accuracy=correct/valid_n,greedy_per_class_accuracy=per_class,
207
  greedy_predicted_vulnerable_fraction=predicted_vulnerable,
208
  greedy_completion_entropy_nats=greedy_diagnostics['entropy_nats'],
 
209
  correct_vulnerable_r2_mean=float(np.mean(correct_vuln_r2)) if correct_vuln_r2 else None,
210
  correct_vulnerable_r2_n=len(correct_vuln_r2),test_touched=False)
211
  path=self.run_dir/f'e4_valid_step_{step:06d}.json'
@@ -362,10 +390,26 @@ def write_progress_report(run_dir,status):
362
  axes[1,0].plot(steps,[x['completion_tokens']['mean'] for x in curves],label='mean')
363
  axes[1,0].plot(steps,[x['completion_tokens']['p95'] for x in curves],label='step p95')
364
  axes[1,0].legend();axes[1,0].set_title('Completion tokens')
365
- for key in ('label_accuracy','val_p_pass_at_1'):
366
- axes[1,1].plot([x['optimizer_step'] for x in validations],
367
- [x[key] for x in validations],'o-',label=key)
368
- axes[1,1].legend();axes[1,1].set_title('Scheduled full VALID; matched diagnostic is separate')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  for ax in axes.flat:
370
  ax.set_xlabel('Optimizer step')
371
  if manifest.get('continuation'):
@@ -375,7 +419,7 @@ def write_progress_report(run_dir,status):
375
  fig.tight_layout();fig.savefig(run_dir/'training_curves.png',dpi=140);plt.close(fig)
376
 
377
 
378
- def worker(run_dir):
379
  import pandas as pd
380
  import torch
381
  from datasets import Dataset
@@ -388,7 +432,7 @@ def worker(run_dir):
388
  from scripts.verify_grpo_reward_equivalence import sha256
389
 
390
  runtime=None;trainer=None;e4=False
391
- start=float(os.environ['SCALE_START_UNIX'])
392
  status=dict(status='initializing',started_at=now(),authorization='Review #20 + D-GRPO-14',
393
  test_touched=False,scale_budget_ceiling_gpu_hours=250,
394
  launch_segment_budget_gpu_hours=40,resume_requires_user=True)
@@ -403,7 +447,22 @@ def worker(run_dir):
403
  e4b=manifest.get('launch_authority')=='D-GRPO-17'
404
  if e4b:status['authorization']='D-GRPO-17'
405
  resume_file=run_dir/'e4b_resume.json'
406
- if e4b and resume_file.is_file():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
  continuation=json.loads(resume_file.read_text())
408
  if continuation.get('source_rule')!='D-GRPO-17' or continuation.get('lr_factor')!=1.0:
409
  raise SmokeStop('E4b_resume_pointer_invalid')
@@ -457,8 +516,13 @@ def worker(run_dir):
457
  runtime.best_p_pass=resume_extra['best_p_pass']
458
  runtime.best_checkpoint=resume_extra['best_checkpoint']
459
  runtime.last_safe_step=continuation['optimizer_step']
460
- prior_valid=[json.loads(x) for x in (resume_source/'valid_curve.jsonl').read_text().splitlines()]
461
- runtime.eval_entropies=[x['entropy_nats'] for x in prior_valid]
 
 
 
 
 
462
  runtime.steps_per_epoch=(len(runtime.train_ids)+63)//64
463
  runtime.progress('loading_fixed_judge')
464
  runtime.judge=FixedJudge(run_dir);runtime.judge.should_log=select_rollout
@@ -565,11 +629,22 @@ def worker(run_dir):
565
  out=trainer.llm.generate([rows[runtime.train_ids[0]]['prompt']],
566
  sampling_params=SamplingParams(temperature=1.,max_tokens=1536,n=1),use_tqdm=False)
567
  record_integration_canary(runtime,trainer,out[0].outputs[0].text)
568
- runtime.progress('training_scale',config_hash=config_hash,train_rows=len(runtime.train_ids),
569
- valid_rows=len(manifest['valid_selection']),wall_cap_hours=40)
570
- trainer.train(resume_from_checkpoint=str(bridge) if bridge else None)
571
- status.update(status='stopped',stop_reason='trainer_reached_max_steps_without_review',
572
- requires_user_review=True)
 
 
 
 
 
 
 
 
 
 
 
573
  except SmokeStop as error:
574
  status.update(status='stopped',stop_reason=str(error),requires_user_review=True)
575
  print('TRIPWIRE_OR_BUDGET_STOP',error,flush=True)
@@ -589,8 +664,11 @@ def worker(run_dir):
589
  if runtime and runtime.curve:
590
  status['aggregate_zero_variance_fraction']=sum(s['zero_groups'] for s in runtime.curve)/(64*len(runtime.curve))
591
  status['aggregate_rollout_accounting']=rollout_accounting(runtime.curve,canary=runtime.canary)
592
- write_json(run_dir/'scale_final_status.json',status)
593
- write_progress_report(run_dir,status)
 
 
 
594
  print('SCALE_FINAL_STATUS',json.dumps(status),flush=True)
595
  if status['status']=='failed':raise SystemExit(2)
596
 
@@ -645,10 +723,12 @@ def supervise(run_dir):
645
 
646
  def main():
647
  parser=argparse.ArgumentParser();parser.add_argument('--worker',action='store_true')
648
- parser.add_argument('--run-dir',type=Path,required=True);args=parser.parse_args()
 
649
  run_dir=args.run_dir.resolve()
650
  if not (run_dir/'run_manifest.json').is_file():raise SystemExit('frozen preflight manifest missing')
651
- if args.worker:worker(run_dir)
 
652
  else:supervise(run_dir)
653
 
654
  if __name__=='__main__':main()
 
39
  return int.from_bytes(hashlib.sha256(key.encode()).digest()[:8], 'big') % 20 == 0
40
 
41
 
42
+ def restore_e4b_eval_history(runtime, run_dir):
43
+ """Carry completed VALID endpoints forward when resuming a full-state run."""
44
+ run_dir=Path(run_dir)
45
+ curve_path=run_dir/'valid_curve.jsonl'
46
+ history=([json.loads(line) for line in curve_path.read_text().splitlines()]
47
+ if curve_path.is_file() else [])
48
+ retry_path=run_dir/'step100_matched_eval_retry/e4_valid_step_000100.json'
49
+ if retry_path.is_file() and not any(int(x.get('optimizer_step',-1))==100 for x in history):
50
+ retry=json.loads(retry_path.read_text())
51
+ history.append(retry)
52
+ append_json(curve_path,retry)
53
+ write_json(run_dir/'valid_step_000100.json',retry)
54
+ runtime.eval_entropies=[value for row in history
55
+ if (value:=row.get('entropy_nats',row.get('greedy_completion_entropy_nats'))) is not None]
56
+ for row in history:
57
+ score=row.get('row_auc')
58
+ if score is not None and score>runtime.best_p_pass:
59
+ runtime.best_p_pass=score
60
+ runtime.best_checkpoint=row.get('checkpoint')
61
+ if runtime.best_checkpoint is not None:
62
+ best_step=max((int(x.get('optimizer_step',0)) for x in history
63
+ if x.get('checkpoint')==runtime.best_checkpoint),default=0)
64
+ write_json(run_dir/'best_checkpoint.json',dict(step=best_step,
65
+ valid_row_auc=runtime.best_p_pass,path=runtime.best_checkpoint,
66
+ selection='primary E4 endpoint row ROC-AUC on chronological VALID'))
67
+
68
+
69
  class ScaleRuntime(Runtime):
70
  sample_weight_fn=staticmethod(bounded_zero_correct_sample_difficulty_weight)
71
 
 
178
  ids=[r['prompt_id'] for r in self.manifest['valid_selection']]
179
  labels={r['prompt_id']:int(r['target']) for r in self.manifest['valid_selection']}
180
  prompts=[self.rows[pid]['prompt'] for pid in ids]
 
181
  sampled=self.trainer.llm.generate(prompts,sampling_params=SamplingParams(
182
  temperature=.8,max_tokens=1536,n=8,seed=42),use_tqdm=True)
183
  records=[];correct_vuln_r2=[]
 
224
  if len(self.eval_entropies)>=2 and all(x<.3 for x in self.eval_entropies[-2:]):
225
  raise SmokeStop('two_consecutive_VALID_entropies_below_0.3 [D-GRPO-9]')
226
  metrics=dict(optimizer_step=step,checkpoint=str(checkpoint),adapter_label='E4 balanced reward',
227
+ measurement_label='E4b step-100 matched eval, post-fix retry of the interrupted measurement',
228
  inference_protocol='E2 exact: 8 generations, temperature 0.8, max_tokens 1536, seed 42',
229
  n_rows=len(records),n_pairs=len({r['pair_id'] for r in records}),
230
  parse_rate=sampled_parse,row_auc=score['auc'],
 
233
  greedy_label_accuracy=correct/valid_n,greedy_per_class_accuracy=per_class,
234
  greedy_predicted_vulnerable_fraction=predicted_vulnerable,
235
  greedy_completion_entropy_nats=greedy_diagnostics['entropy_nats'],
236
+ entropy_nats=greedy_diagnostics['entropy_nats'],
237
  correct_vulnerable_r2_mean=float(np.mean(correct_vuln_r2)) if correct_vuln_r2 else None,
238
  correct_vulnerable_r2_n=len(correct_vuln_r2),test_touched=False)
239
  path=self.run_dir/f'e4_valid_step_{step:06d}.json'
 
390
  axes[1,0].plot(steps,[x['completion_tokens']['mean'] for x in curves],label='mean')
391
  axes[1,0].plot(steps,[x['completion_tokens']['p95'] for x in curves],label='step p95')
392
  axes[1,0].legend();axes[1,0].set_title('Completion tokens')
393
+ if is_e4:
394
+ # E4 uses the E2-matched sampled protocol. Its schema intentionally
395
+ # reports row_auc and greedy_label_accuracy, not the older
396
+ # label_accuracy / val_p_pass_at_1 pair.
397
+ for key, label in (('row_auc','row AUC'),
398
+ ('greedy_label_accuracy','greedy accuracy')):
399
+ points=[x for x in validations if x.get(key) is not None]
400
+ if points:
401
+ axes[1,1].plot([x['optimizer_step'] for x in points],
402
+ [x[key] for x in points],'o-',label=label)
403
+ axes[1,1].set_title('E2-matched VALID AUC; greedy accuracy is secondary')
404
+ else:
405
+ for key in ('label_accuracy','val_p_pass_at_1'):
406
+ points=[x for x in validations if x.get(key) is not None]
407
+ if points:
408
+ axes[1,1].plot([x['optimizer_step'] for x in points],
409
+ [x[key] for x in points],'o-',label=key)
410
+ axes[1,1].set_title('Scheduled full VALID; matched diagnostic is separate')
411
+ if axes[1,1].lines:
412
+ axes[1,1].legend()
413
  for ax in axes.flat:
414
  ax.set_xlabel('Optimizer step')
415
  if manifest.get('continuation'):
 
419
  fig.tight_layout();fig.savefig(run_dir/'training_curves.png',dpi=140);plt.close(fig)
420
 
421
 
422
+ def worker(run_dir, eval_only_step=None):
423
  import pandas as pd
424
  import torch
425
  from datasets import Dataset
 
432
  from scripts.verify_grpo_reward_equivalence import sha256
433
 
434
  runtime=None;trainer=None;e4=False
435
+ start=float(os.environ.get('SCALE_START_UNIX',time.time()))
436
  status=dict(status='initializing',started_at=now(),authorization='Review #20 + D-GRPO-14',
437
  test_touched=False,scale_budget_ceiling_gpu_hours=250,
438
  launch_segment_budget_gpu_hours=40,resume_requires_user=True)
 
447
  e4b=manifest.get('launch_authority')=='D-GRPO-17'
448
  if e4b:status['authorization']='D-GRPO-17'
449
  resume_file=run_dir/'e4b_resume.json'
450
+ if eval_only_step is not None:
451
+ if not e4b or eval_only_step != 100:
452
+ raise SmokeStop('only_the_authorized_E4b_step100_eval_retry_is_supported')
453
+ from scripts.verify_grpo_reward_equivalence import sha256
454
+ from src.rl.full_state_checkpoint import verify_full_state
455
+ checkpoint=run_dir/'checkpoints'/f'step-{eval_only_step:06d}'
456
+ if not verify_full_state(checkpoint,expected_base_revision=manifest['policy']['base_revision']):
457
+ raise SmokeStop('step100_eval_checkpoint_integrity_failure')
458
+ adapter_hash=sha256(checkpoint/'adapter/adapter_model.safetensors')
459
+ continuation=dict(source_rule='D-GRPO-17',source_run=run_dir.relative_to(ROOT).as_posix(),
460
+ checkpoint=(checkpoint.relative_to(ROOT).as_posix()),optimizer_step=eval_only_step,
461
+ lr_factor=1.0,adapter_sha256=adapter_hash,adam_reset=False,scheduler_reset=False)
462
+ manifest['continuation']=continuation
463
+ status.update(authorization='Review #28 step-100 standalone matched-eval retry',
464
+ eval_only=True,eval_checkpoint=str(checkpoint),resume_optimizer_step=eval_only_step)
465
+ elif e4b and resume_file.is_file():
466
  continuation=json.loads(resume_file.read_text())
467
  if continuation.get('source_rule')!='D-GRPO-17' or continuation.get('lr_factor')!=1.0:
468
  raise SmokeStop('E4b_resume_pointer_invalid')
 
516
  runtime.best_p_pass=resume_extra['best_p_pass']
517
  runtime.best_checkpoint=resume_extra['best_checkpoint']
518
  runtime.last_safe_step=continuation['optimizer_step']
519
+ if e4b:
520
+ restore_e4b_eval_history(runtime,run_dir)
521
+ else:
522
+ valid_curve_path=resume_source/'valid_curve.jsonl'
523
+ prior_valid=([json.loads(x) for x in valid_curve_path.read_text().splitlines()]
524
+ if valid_curve_path.is_file() else [])
525
+ runtime.eval_entropies=[x['entropy_nats'] for x in prior_valid]
526
  runtime.steps_per_epoch=(len(runtime.train_ids)+63)//64
527
  runtime.progress('loading_fixed_judge')
528
  runtime.judge=FixedJudge(run_dir);runtime.judge.should_log=select_rollout
 
629
  out=trainer.llm.generate([rows[runtime.train_ids[0]]['prompt']],
630
  sampling_params=SamplingParams(temperature=1.,max_tokens=1536,n=1),use_tqdm=False)
631
  record_integration_canary(runtime,trainer,out[0].outputs[0].text)
632
+ if eval_only_step is not None:
633
+ trainer.state.global_step=eval_only_step
634
+ runtime.run_dir=run_dir/'step100_matched_eval_retry'
635
+ runtime.run_dir.mkdir(parents=True,exist_ok=True)
636
+ runtime.progress('e4b_step100_matched_eval_retry',checkpoint=str(resume_checkpoint),
637
+ protocol='E2 exact: n=8, temperature=0.8, max_tokens=1536, seed=42')
638
+ metrics=runtime.evaluate_e4_matched(eval_only_step,resume_checkpoint)
639
+ status.update(status='eval_only_complete',metrics_path=str(runtime.run_dir/'e4_valid_step_000100.json'),
640
+ row_auc=metrics['row_auc'],auc_delta_vs_sft500=metrics['auc_delta_vs_sft500'],
641
+ sampled_parse_rate=metrics['parse_rate'],gpu_wall_hours=(time.time()-start)/3600)
642
+ else:
643
+ runtime.progress('training_scale',config_hash=config_hash,train_rows=len(runtime.train_ids),
644
+ valid_rows=len(manifest['valid_selection']),wall_cap_hours=40)
645
+ trainer.train(resume_from_checkpoint=str(bridge) if bridge else None)
646
+ status.update(status='stopped',stop_reason='trainer_reached_max_steps_without_review',
647
+ requires_user_review=True)
648
  except SmokeStop as error:
649
  status.update(status='stopped',stop_reason=str(error),requires_user_review=True)
650
  print('TRIPWIRE_OR_BUDGET_STOP',error,flush=True)
 
664
  if runtime and runtime.curve:
665
  status['aggregate_zero_variance_fraction']=sum(s['zero_groups'] for s in runtime.curve)/(64*len(runtime.curve))
666
  status['aggregate_rollout_accounting']=rollout_accounting(runtime.curve,canary=runtime.canary)
667
+ status_path=(run_dir/'e4b_step100_eval_worker_status.json' if eval_only_step is not None
668
+ else run_dir/'scale_final_status.json')
669
+ write_json(status_path,status)
670
+ if eval_only_step is None:
671
+ write_progress_report(run_dir,status)
672
  print('SCALE_FINAL_STATUS',json.dumps(status),flush=True)
673
  if status['status']=='failed':raise SystemExit(2)
674
 
 
723
 
724
  def main():
725
  parser=argparse.ArgumentParser();parser.add_argument('--worker',action='store_true')
726
+ parser.add_argument('--run-dir',type=Path,required=True)
727
+ parser.add_argument('--eval-only-step',type=int);args=parser.parse_args()
728
  run_dir=args.run_dir.resolve()
729
  if not (run_dir/'run_manifest.json').is_file():raise SystemExit('frozen preflight manifest missing')
730
+ if args.eval_only_step is not None:worker(run_dir,eval_only_step=args.eval_only_step)
731
+ elif args.worker:worker(run_dir)
732
  else:supervise(run_dir)
733
 
734
  if __name__=='__main__':main()
scripts/stage_review30_test_eval.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Stage the one-time final TEST evaluation without opening TEST data.
2
+
3
+ This dry run validates the cached E4b VALID result schema and records the frozen
4
+ four-system evaluation plan. It intentionally has no code path that reads a split
5
+ file or invokes a model.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from pathlib import Path
11
+
12
+ ROOT = Path(__file__).resolve().parents[1]
13
+ VALID_FIXTURE = ROOT / "results/phase6/review26/e4b_balanced_reward/e4_valid_step_000200.json"
14
+ OUTPUT = ROOT / "results/phase10/test_staging/dry_run.json"
15
+
16
+
17
+ def main() -> dict:
18
+ record = json.loads(VALID_FIXTURE.read_text())
19
+ required = {"optimizer_step", "row_auc", "row_auc_pair_cluster_95_ci", "parse_rate",
20
+ "greedy_label_accuracy", "greedy_per_class_accuracy", "test_touched"}
21
+ missing = sorted(required - record.keys())
22
+ if missing:
23
+ raise ValueError(f"VALID fixture missing required metric fields: {missing}")
24
+ if record["test_touched"] is not False:
25
+ raise ValueError("VALID fixture indicates TEST was touched")
26
+ result = {
27
+ "status": "valid_fixture_schema_pass",
28
+ "fixture": str(VALID_FIXTURE.relative_to(ROOT)),
29
+ "fixture_step": record["optimizer_step"],
30
+ "fixture_auc": record["row_auc"],
31
+ "fixture_parse_rate": record["parse_rate"],
32
+ "metrics_schema": sorted(required),
33
+ "final_test_systems": ["classical pipeline", "SFT-500", "GRPO-324", "E4b step-200"],
34
+ "final_test_protocol": "E2-matched; accuracy + Wilson; per-class accuracy; row AUC + pair-cluster CI; IoU; P-Pass@1; trace validity",
35
+ "final_test_execution_authorized": False,
36
+ "test_split_opened": False,
37
+ "model_inference_run": False,
38
+ "note": "Dry run uses a cached chronological VALID result only; TEST path was not enumerated or read.",
39
+ }
40
+ OUTPUT.parent.mkdir(parents=True, exist_ok=True)
41
+ OUTPUT.write_text(json.dumps(result, indent=2) + "\n")
42
+ print(json.dumps(result, indent=2))
43
+ return result
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()
scripts/tracegrpo-e4b.service CHANGED
@@ -11,7 +11,7 @@ Environment=HF_HUB_OFFLINE=1
11
  Environment=TOKENIZERS_PARALLELISM=false
12
  Environment=PYTHONUNBUFFERED=1
13
  ExecStartPre=+/usr/bin/systemctl stop qwen3-32b.service
14
- ExecStart=/home/ubuntu/ib_connect_research/project/tracegrpo/.venv/bin/python -u /home/ubuntu/ib_connect_research/project/tracegrpo/scripts/run_review26_e4b_supervisor.py
15
  Restart=on-failure
16
  RestartSec=30
17
  KillMode=control-group
 
11
  Environment=TOKENIZERS_PARALLELISM=false
12
  Environment=PYTHONUNBUFFERED=1
13
  ExecStartPre=+/usr/bin/systemctl stop qwen3-32b.service
14
+ ExecStart=/home/ubuntu/ib_connect_research/project/tracegrpo/.venv/bin/python -u -m scripts.run_review26_e4b_supervisor
15
  Restart=on-failure
16
  RestartSec=30
17
  KillMode=control-group
scripts/verify_complete_hf_archives.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Stream every recovery member and compare with the authoritative file inventory."""
3
+ import argparse
4
+ import hashlib
5
+ import json
6
+ import tarfile
7
+ from pathlib import Path
8
+
9
+ def verify(root):
10
+ m=json.loads((root/'SNAPSHOT_MANIFEST.json').read_text());reports=[]
11
+ for archive in m['archives']:
12
+ expected={r['path']:r for r in m['files'] if r['archive']==archive['path']};actual={}
13
+ h=hashlib.sha256()
14
+ with (root/archive['path']).open('rb') as stream:
15
+ for block in iter(lambda:stream.read(8*1024*1024),b''):h.update(block)
16
+ if h.hexdigest()!=archive['sha256']:raise ValueError('Archive SHA mismatch: '+archive['path'])
17
+ with tarfile.open(root/archive['path'],'r|gz') as tar:
18
+ for member in tar:
19
+ if member.name=='BUNDLE_MANIFEST.json':
20
+ inner=json.loads(tar.extractfile(member).read())
21
+ if {r['path'] for r in inner['files']}!=set(expected):raise ValueError('Bundle inventory mismatch')
22
+ continue
23
+ if member.islnk():
24
+ if member.linkname not in actual:raise ValueError('Missing hard-link target')
25
+ actual[member.name]=actual[member.linkname];continue
26
+ if not member.isfile():raise ValueError('Unexpected non-file archive member')
27
+ h=hashlib.sha256();size=0;stream=tar.extractfile(member)
28
+ for block in iter(lambda:stream.read(8*1024*1024),b''):h.update(block);size+=len(block)
29
+ actual[member.name]={'sha256':h.hexdigest(),'bytes':size}
30
+ if set(actual)!=set(expected):raise ValueError('Member set mismatch: '+archive['path'])
31
+ for path,row in expected.items():
32
+ if actual[path]['sha256']!=row['sha256'] or actual[path]['bytes']!=row['bytes']:raise ValueError('File content mismatch: '+path)
33
+ rec={'archive':archive['path'],'verified_files':len(actual),'archive_sha256':archive['sha256'],'all_member_hashes_match':True};reports.append(rec);print(json.dumps(rec),flush=True)
34
+ status={'status':'verified','archives':reports,'total_files':sum(r['verified_files'] for r in reports),'test_evaluated':False,'models_loaded':False}
35
+ (root/'ARCHIVE_VERIFICATION.json').write_text(json.dumps(status,indent=2)+'\n');return status
36
+
37
+ if __name__=='__main__':
38
+ p=argparse.ArgumentParser();p.add_argument('release',type=Path);a=p.parse_args();verify(a.release)
src/baselines/__init__.py CHANGED
@@ -0,0 +1 @@
 
 
1
+ """Frozen classical baselines and artifact loaders."""
src/baselines/classical_pipeline.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Persisted Phase 7 character detector and line-localizer components."""
2
+ from __future__ import annotations
3
+
4
+ import hashlib
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import joblib
10
+ import numpy as np
11
+ import pandas as pd
12
+ from sklearn.feature_extraction.text import TfidfVectorizer
13
+ from sklearn.linear_model import SGDClassifier
14
+
15
+ from scripts.run_line_localization_baseline import materialize
16
+
17
+ LABEL_CONFIG = dict(analyzer="char", ngram_range=(3, 5), min_df=2,
18
+ max_features=300_000, sublinear_tf=True, dtype=np.float32)
19
+ LABEL_MODEL_CONFIG = dict(loss="log_loss", alpha=1e-5, max_iter=200, tol=1e-3,
20
+ random_state=42, average=True)
21
+ LINE_CONFIG = dict(analyzer="char", ngram_range=(2, 5), min_df=2,
22
+ max_features=250_000, sublinear_tf=True, dtype=np.float32)
23
+ LINE_MODEL_CONFIG = dict(loss="log_loss", alpha=1e-5, max_iter=30, tol=1e-3,
24
+ random_state=42, average=True, class_weight="balanced")
25
+ ARTIFACT_FILES = {
26
+ "label_vectorizer": "label_vectorizer.joblib",
27
+ "label_classifier": "label_classifier.joblib",
28
+ "line_vectorizer": "line_vectorizer.joblib",
29
+ "line_localizer": "line_localizer.joblib",
30
+ }
31
+
32
+
33
+ def sha256_file(path: Path) -> str:
34
+ digest = hashlib.sha256()
35
+ with path.open("rb") as stream:
36
+ for chunk in iter(lambda: stream.read(1024 * 1024), b""):
37
+ digest.update(chunk)
38
+ return digest.hexdigest()
39
+
40
+
41
+ def train_pair_texts(frame: pd.DataFrame, pair_ids: set[str]) -> tuple[list[str], np.ndarray]:
42
+ texts: list[str] = []
43
+ labels: list[int] = []
44
+ subset = frame[frame["pair_id"].astype(str).isin(pair_ids)]
45
+ for pair_id, group in subset.groupby("pair_id", sort=True):
46
+ if len(group) != 2 or set(group["target"].astype(int)) != {0, 1}:
47
+ raise ValueError(f"label pair integrity failure: {pair_id}")
48
+ for target in (0, 1):
49
+ row = group[group["target"].astype(int) == target].iloc[0]
50
+ texts.append(str(row["func_vuln"] if target else row["func_patch"]))
51
+ labels.append(target)
52
+ return texts, np.asarray(labels, dtype=np.int8)
53
+
54
+
55
+ def fit_and_save(corpus: Path, train_split: Path, annotations: Path,
56
+ artifact_dir: Path) -> dict[str, Any]:
57
+ train_ids = set(map(str, json.loads(train_split.read_text())))
58
+ frame = pd.read_parquet(corpus)
59
+ texts, labels = train_pair_texts(frame, train_ids)
60
+ label_vectorizer = TfidfVectorizer(**LABEL_CONFIG)
61
+ x_label = label_vectorizer.fit_transform(texts)
62
+ label_classifier = SGDClassifier(**LABEL_MODEL_CONFIG).fit(x_label, labels)
63
+
64
+ train_examples, missing, out_of_range = materialize(corpus, train_split, annotations)
65
+ line_docs = [candidate for ex in train_examples for candidate in ex["candidates"]]
66
+ line_labels = np.asarray([int(i + 1 in ex["gold"])
67
+ for ex in train_examples for i in range(ex["n_lines"])], dtype=np.int8)
68
+ if missing or out_of_range or not line_labels.any():
69
+ raise ValueError(f"TRAIN localization targets invalid: missing={missing}, out_of_range={out_of_range}")
70
+ line_vectorizer = TfidfVectorizer(**LINE_CONFIG)
71
+ x_line = line_vectorizer.fit_transform(line_docs)
72
+ line_localizer = SGDClassifier(**LINE_MODEL_CONFIG).fit(x_line, line_labels)
73
+
74
+ artifact_dir.mkdir(parents=True, exist_ok=True)
75
+ objects = locals()
76
+ for key, filename in ARTIFACT_FILES.items():
77
+ joblib.dump(objects[key], artifact_dir / filename, compress=3)
78
+ manifest = {
79
+ "artifact_version": "phase7_classical_v1",
80
+ "fit_scope": "chronological TRAIN only",
81
+ "train_pairs": len(train_ids),
82
+ "train_rows": len(texts),
83
+ "train_line_candidates": len(line_labels),
84
+ "train_positive_lines": int(line_labels.sum()),
85
+ "seed": 42,
86
+ "label_vectorizer_config": {**LABEL_CONFIG, "dtype": "float32"},
87
+ "label_classifier_config": LABEL_MODEL_CONFIG,
88
+ "line_vectorizer_config": {**LINE_CONFIG, "dtype": "float32"},
89
+ "line_localizer_config": LINE_MODEL_CONFIG,
90
+ "versions": {"sklearn": __import__("sklearn").__version__, "numpy": np.__version__,
91
+ "pandas": pd.__version__, "joblib": joblib.__version__},
92
+ "inputs_sha256": {p.name: sha256_file(p) for p in (corpus, train_split, annotations)},
93
+ "test_read": False,
94
+ "artifacts": {key: {"path": filename, "sha256": sha256_file(artifact_dir / filename)}
95
+ for key, filename in ARTIFACT_FILES.items()},
96
+ }
97
+ (artifact_dir / "manifest.json").write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
98
+ return manifest
99
+
100
+
101
+ def load_pipeline(artifact_dir: Path, *, verify_hashes: bool = True) -> dict[str, Any]:
102
+ manifest = json.loads((artifact_dir / "manifest.json").read_text())
103
+ if manifest.get("artifact_version") != "phase7_classical_v1":
104
+ raise ValueError("Unsupported classical artifact version")
105
+ loaded = {}
106
+ for key, filename in ARTIFACT_FILES.items():
107
+ path = artifact_dir / filename
108
+ if verify_hashes and sha256_file(path) != manifest["artifacts"][key]["sha256"]:
109
+ raise ValueError(f"Artifact hash mismatch: {filename}")
110
+ loaded[key] = joblib.load(path)
111
+ loaded["manifest"] = manifest
112
+ return loaded
113
+
114
+
115
+ def predict_labels(pipeline: dict[str, Any], frame: pd.DataFrame,
116
+ pair_ids: set[str]) -> list[dict[str, Any]]:
117
+ texts, labels = train_pair_texts(frame, pair_ids)
118
+ subset = frame[frame["pair_id"].astype(str).isin(pair_ids)]
119
+ rows = []
120
+ for pair_id, group in subset.groupby("pair_id", sort=True):
121
+ for target in (0, 1):
122
+ row = group[group["target"].astype(int) == target].iloc[0]
123
+ rows.append({"sample_id": str(row["sample_id"]), "pair_id": str(pair_id), "target": target})
124
+ # train_pair_texts guarantees the same pair/label ordering as rows.
125
+ scores = pipeline["label_classifier"].decision_function(
126
+ pipeline["label_vectorizer"].transform(texts))
127
+ predictions = pipeline["label_classifier"].predict(
128
+ pipeline["label_vectorizer"].transform(texts)).astype(int)
129
+ if len(rows) != len(labels):
130
+ raise AssertionError("Label metadata/prediction alignment failure")
131
+ return [row | {"decision_score": float(score), "pred_target": int(pred)}
132
+ for row, score, pred in zip(rows, scores, predictions, strict=True)]
src/rl/live_adapter.py CHANGED
@@ -8,7 +8,9 @@ from __future__ import annotations
8
  from dataclasses import dataclass
9
  import hashlib
10
  import json
 
11
  import shutil
 
12
  from pathlib import Path
13
 
14
 
@@ -25,7 +27,7 @@ class AdapterSnapshot:
25
 
26
 
27
  def publish_live_adapter(model, root: Path, step: int, base_revision: str) -> AdapterSnapshot:
28
- """Publish an immutable adapter-only copy of the current policy state."""
29
  configs = model.peft_config
30
  if len(configs) != 1:
31
  raise ValueError("D-GRPO-3 requires exactly one shared adapter")
@@ -38,21 +40,44 @@ def publish_live_adapter(model, root: Path, step: int, base_revision: str) -> Ad
38
  raise ValueError("adapter step and pinned base revision are required")
39
  if any(getattr(module, "merged", False) for module in model.modules()):
40
  raise ValueError("D-GRPO-1 forbids merged policy layers")
41
- destination = root.resolve() / f"adapter-step-{step:06d}"
42
- destination.mkdir(parents=True, exist_ok=False)
43
- model.save_pretrained(destination, safe_serialization=True, selected_adapters=[name])
44
- weight_file = destination / "adapter_model.safetensors"
45
- if not weight_file.is_file():
46
- raise ValueError("adapter-only publication has no adapter weights")
47
- if any(destination.glob("model*.safetensors")):
48
- raise ValueError("unexpected base/merged weights in adapter publication")
49
- weights_sha = hashlib.sha256(weight_file.read_bytes()).hexdigest()
50
- snapshot = AdapterSnapshot(step, destination, weights_sha, base_revision)
51
- (destination / "policy_provenance.json").write_text(json.dumps({
52
- "adapter_step": step, "pinned_base_revision": base_revision,
53
- "adapter_weights_sha256": weights_sha, "merged": False,
54
- }, indent=2) + "\n")
55
- return snapshot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
 
58
  class NativeAdapterLLM:
 
8
  from dataclasses import dataclass
9
  import hashlib
10
  import json
11
+ import os
12
  import shutil
13
+ import tempfile
14
  from pathlib import Path
15
 
16
 
 
27
 
28
 
29
  def publish_live_adapter(model, root: Path, step: int, base_revision: str) -> AdapterSnapshot:
30
+ """Publish an immutable adapter copy; reuse an identical same-step publication."""
31
  configs = model.peft_config
32
  if len(configs) != 1:
33
  raise ValueError("D-GRPO-3 requires exactly one shared adapter")
 
40
  raise ValueError("adapter step and pinned base revision are required")
41
  if any(getattr(module, "merged", False) for module in model.modules()):
42
  raise ValueError("D-GRPO-1 forbids merged policy layers")
43
+ root = root.resolve()
44
+ root.mkdir(parents=True, exist_ok=True)
45
+ destination = root / f"adapter-step-{step:06d}"
46
+ # Serialize to a temporary directory first. If this step was already
47
+ # published, compare bytes and provenance before reusing it; a same-step
48
+ # but changed policy is a hard error, never a silent overwrite.
49
+ with tempfile.TemporaryDirectory(prefix=f".adapter-step-{step:06d}-", dir=root) as temp:
50
+ staged = Path(temp)
51
+ model.save_pretrained(staged, safe_serialization=True, selected_adapters=[name])
52
+ staged_weights = staged / "adapter_model.safetensors"
53
+ if not staged_weights.is_file():
54
+ raise ValueError("adapter-only publication has no adapter weights")
55
+ if any(staged.glob("model*.safetensors")):
56
+ raise ValueError("unexpected base/merged weights in adapter publication")
57
+ weights_sha = hashlib.sha256(staged_weights.read_bytes()).hexdigest()
58
+ provenance = {
59
+ "adapter_step": step, "pinned_base_revision": base_revision,
60
+ "adapter_weights_sha256": weights_sha, "merged": False,
61
+ }
62
+ if destination.exists():
63
+ weight_file = destination / "adapter_model.safetensors"
64
+ provenance_file = destination / "policy_provenance.json"
65
+ try:
66
+ existing = json.loads(provenance_file.read_text())
67
+ existing_sha = hashlib.sha256(weight_file.read_bytes()).hexdigest()
68
+ except (OSError, ValueError, json.JSONDecodeError) as exc:
69
+ raise ValueError("existing same-step adapter publication is incomplete") from exc
70
+ if existing != provenance or existing_sha != weights_sha:
71
+ raise ValueError("same-step adapter publication differs from current policy")
72
+ return AdapterSnapshot(step, destination, weights_sha, base_revision)
73
+ (staged / "policy_provenance.json").write_text(json.dumps(provenance, indent=2) + "\n")
74
+ try:
75
+ os.rename(staged, destination)
76
+ except FileExistsError:
77
+ # A concurrent publisher may have won the rename. Validate its
78
+ # immutable contents on the next invocation rather than overwrite.
79
+ raise
80
+ return AdapterSnapshot(step, destination, weights_sha, base_revision)
81
 
82
 
83
  class NativeAdapterLLM: