88import hashlib
99import json
1010import os
11- import plistlib
1211import re
1312import shutil
1413import socket
@@ -239,15 +238,20 @@ def repair_candidate_schema(
239238 "missing lemma."
240239 )
241240 changed .append ("critic_directive" )
242- if not repaired .get ("prefill_compute_chunk_tokens" ):
243- repaired ["prefill_compute_chunk_tokens" ] = int (
244- current ["prefill_compute_chunk_tokens" ],
245- )
241+ fixed_chunk_tokens = int (current ["prefill_compute_chunk_tokens" ])
242+ proposed_chunk_tokens = repaired .get ("prefill_compute_chunk_tokens" )
243+ try :
244+ proposed_chunk_tokens = int (proposed_chunk_tokens )
245+ except (TypeError , ValueError ):
246+ proposed_chunk_tokens = None
247+ if (
248+ proposed_chunk_tokens is None
249+ or int (proposed_chunk_tokens ) != fixed_chunk_tokens
250+ ):
251+ repaired ["prefill_compute_chunk_tokens" ] = fixed_chunk_tokens
246252 changed .append ("prefill_compute_chunk_tokens" )
247253 else :
248- repaired ["prefill_compute_chunk_tokens" ] = int (
249- repaired ["prefill_compute_chunk_tokens" ],
250- )
254+ repaired ["prefill_compute_chunk_tokens" ] = fixed_chunk_tokens
251255 return repaired , changed
252256
253257
@@ -502,7 +506,8 @@ def propose_candidate(
502506 "program exactly. Select one unresolved proof obligation and propose "
503507 "one falsifiable GAN strategy experiment. Return JSON only with keys: "
504508 + ", " .join (REQUIRED_CANDIDATE_FIELDS )
505- + ". Allowed prefill_compute_chunk_tokens: 64, 128, 256. "
509+ + ". prefill_compute_chunk_tokens is immutable and must equal "
510+ f"{ current ['prefill_compute_chunk_tokens' ]} . "
506511 "Do not weaken full context, final-only snapshots, or no-fallback rules."
507512 " The hypothesis must not repeat any hypothesis or hash in RESULTS. "
508513 "It must either construct a concrete object or attempt a concrete "
@@ -585,91 +590,20 @@ def propose_candidate(
585590 return candidate
586591
587592
588- def deploy_candidate (worker_ssh : str , chunk_tokens : int ) -> None :
589- remote = f"""python3 - <<'PY'
590- import os, plistlib
591- from pathlib import Path
592- p=Path.home()/'Library/LaunchAgents/ai.kakeya.prefill-worker.plist'
593- d=plistlib.loads(p.read_bytes())
594- a=d['ProgramArguments']
595- i=a.index('--prefill-compute-chunk-tokens')
596- a[i+1]='{ chunk_tokens } '
597- t=p.with_suffix('.plist.tmp')
598- t.write_bytes(plistlib.dumps(d))
599- os.chmod(t,0o644)
600- t.replace(p)
601- PY
602- domain=gui/$(id -u)
603- label=ai.kakeya.prefill-worker
604- service=\" $domain/$label\"
605- plist=\" $HOME/Library/LaunchAgents/$label.plist\"
606- launchctl bootout \" $service\" 2>/dev/null || true
607- for delay in 1 1 2 3 5; do
608- if ! launchctl print \" $service\" >/dev/null 2>&1; then
609- break
610- fi
611- sleep \" $delay\"
612- done
613- if launchctl print \" $service\" >/dev/null 2>&1; then
614- echo \" worker service did not unload\" >&2
615- exit 70
616- fi
617- loaded=0
618- for delay in 1 2 3 5; do
619- if launchctl bootstrap \" $domain\" \" $plist\" ; then
620- loaded=1
621- break
622- fi
623- if launchctl print \" $service\" >/dev/null 2>&1; then
624- loaded=1
625- break
626- fi
627- sleep \" $delay\"
628- done
629- if [ \" $loaded\" -ne 1 ]; then
630- echo \" worker service did not bootstrap\" >&2
631- exit 71
632- fi
633- launchctl kickstart -k \" $service\"
634- for attempt in $(seq 1 120); do
635- if nc -G 2 -z 127.0.0.1 53051 >/dev/null 2>&1; then
636- exit 0
637- fi
638- if ! launchctl print \" $service\" >/dev/null 2>&1; then
639- echo \" worker service disappeared during startup\" >&2
640- exit 72
641- fi
642- sleep 1
643- done
644- echo \" worker did not become ready on port 53051\" >&2
645- exit 73
646- """
647- subprocess .run (
648- ["ssh" , "-o" , "BatchMode=yes" , worker_ssh , remote ],
649- check = True ,
650- )
651- _wait_port ("169.254.27.104" , 53051 )
652- probe = subprocess .run (
653- ["ssh" , worker_ssh , "ps -ax -o command=" ],
654- check = True ,
655- capture_output = True ,
656- text = True ,
657- ).stdout
658- expected = f"--prefill-compute-chunk-tokens { chunk_tokens } "
659- if expected not in probe :
660- raise RuntimeError ("deployed worker chunk size verification failed" )
661-
662-
663- def clear_primary_cache () -> None :
664- subprocess .run (
665- [
666- "launchctl" , "kickstart" , "-k" ,
667- f"gui/{ os .getuid ()} /ai.kakeya.grpc-runtime-prefill" ,
668- ],
669- check = True ,
670- )
593+ def check_runtime_health (
594+ worker_address : str ,
595+ dashboard : str = "http://127.0.0.1:8090" ,
596+ ) -> dict :
597+ worker_host , worker_port_text = worker_address .rsplit (":" , 1 )
598+ _wait_port (worker_host , int (worker_port_text ))
671599 _wait_port ("127.0.0.1" , 51051 )
672600 _wait_port ("127.0.0.1" , 8090 )
601+ summary = _json_request (
602+ f"{ dashboard .rstrip ('/' )} /v1/network/summary" ,
603+ )
604+ if int (summary .get ("online_nodes" , 0 )) < 1 :
605+ raise RuntimeError ("prefill fleet has no online worker" )
606+ return summary
673607
674608
675609def _backup (path : Path ) -> bytes | None :
@@ -841,7 +775,6 @@ def run_iteration(args, iteration: int) -> dict:
841775 previous_candidate = candidate_path .read_bytes ()
842776 previous_state = _backup (state_path )
843777 previous_ledger = _backup (ledger_path )
844- previous_chunk = int (current ["prefill_compute_chunk_tokens" ])
845778
846779 proposed = current
847780 gan_completed = False
@@ -854,11 +787,19 @@ def run_iteration(args, iteration: int) -> dict:
854787 try :
855788 print (
856789 f"[autoresearch] iteration={ iteration } "
857- f"phase=predeploy-current candidate={ current ['candidate_id' ]} " ,
790+ f"phase=runtime-health-check candidate={ current ['candidate_id' ]} " ,
791+ flush = True ,
792+ )
793+ health = check_runtime_health (
794+ args .worker_address ,
795+ args .dashboard ,
796+ )
797+ print (
798+ "[autoresearch] phase=runtime-healthy "
799+ f"online_nodes={ health .get ('online_nodes' , 0 )} "
800+ f"kv_hit_rate={ health .get ('kv_hit_rate' , 0 ):.1%} " ,
858801 flush = True ,
859802 )
860- deploy_candidate (args .worker_ssh , previous_chunk )
861- clear_primary_cache ()
862803 if baseline is None and iteration == 0 :
863804 print (
864805 "[autoresearch] phase=baseline using current candidate" ,
@@ -893,11 +834,6 @@ def run_iteration(args, iteration: int) -> dict:
893834 f"target={ proposed ['target_obligation_id' ]} " ,
894835 flush = True ,
895836 )
896- deploy_candidate (
897- args .worker_ssh ,
898- proposed ["prefill_compute_chunk_tokens" ],
899- )
900- clear_primary_cache ()
901837 validate_candidate (proposed )
902838 hypothesis_sha256 = hashlib .sha256 (
903839 proposed ["hypothesis" ].strip ().lower ().encode (),
@@ -992,7 +928,6 @@ def run_iteration(args, iteration: int) -> dict:
992928 append_result (results_path , row )
993929 if not keep :
994930 candidate_path .write_bytes (previous_candidate )
995- deploy_candidate (args .worker_ssh , previous_chunk )
996931 print (
997932 "[autoresearch] phase=candidate-reverted "
998933 "completed-run-preserved" ,
@@ -1010,14 +945,6 @@ def run_iteration(args, iteration: int) -> dict:
1010945 if not gan_completed :
1011946 _restore (state_path , previous_state )
1012947 _restore (ledger_path , previous_ledger )
1013- try :
1014- deploy_candidate (args .worker_ssh , previous_chunk )
1015- except Exception as rollback_exc :
1016- print (
1017- "[autoresearch] phase=rollback-worker-failed "
1018- f"error={ type (rollback_exc ).__name__ } : { rollback_exc } " ,
1019- flush = True ,
1020- )
1021948 if not gan_completed :
1022949 raise
1023950 row = {
@@ -1054,8 +981,12 @@ def run_iteration(args, iteration: int) -> dict:
1054981def main () -> int :
1055982 parser = argparse .ArgumentParser ()
1056983 parser .add_argument ("--iterations" , type = int , default = 1 )
1057- parser .add_argument ("--worker-ssh" , default = "allens" )
984+ parser .add_argument (
985+ "--worker-address" ,
986+ default = "169.254.27.104:53051" ,
987+ )
1058988 parser .add_argument ("--address" , default = "127.0.0.1:51051" )
989+ parser .add_argument ("--dashboard" , default = "http://127.0.0.1:8090" )
1059990 parser .add_argument (
1060991 "--tokenizer-id" ,
1061992 default = str (
0 commit comments