Skip to content

Commit cdece20

Browse files
fluffy314cursoragent
authored andcommitted
fix(autoresearch): deploy current worker before proposal
Predeploy and verify the current candidate before Strategy Agent inference so stale worker code cannot reject the proposal Prefill before experiment orchestration begins. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 1ab80f6 commit cdece20

2 files changed

Lines changed: 80 additions & 20 deletions

File tree

autoresearch/prefill/supervisor.py

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -340,27 +340,57 @@ def run_iteration(args, iteration: int) -> dict:
340340
previous_ledger = _backup(ledger_path)
341341
previous_chunk = int(current["prefill_compute_chunk_tokens"])
342342

343-
if baseline is None and iteration == 0:
344-
proposed = current
345-
else:
346-
proposed = propose_candidate(
347-
address=args.address,
348-
tokenizer_id=args.tokenizer_id,
349-
program=program,
350-
current=current,
351-
results_text=results_path.read_text() if results_path.exists() else "",
352-
ledger=json.loads(ledger_path.read_text()),
353-
)
354-
candidate_path.write_text(render_candidate(proposed))
355-
validate_candidate(proposed)
356-
experiment_id = (
357-
f"ar_{int(time.time())}_{iteration}_"
358-
f"{hashlib.sha256(candidate_path.read_bytes()).hexdigest()[:8]}"
359-
)
360-
report_path = reports_dir / f"{experiment_id}.json"
343+
proposed = current
361344
try:
362-
deploy_candidate(args.worker_ssh, proposed["prefill_compute_chunk_tokens"])
345+
print(
346+
f"[autoresearch] iteration={iteration} "
347+
f"phase=predeploy-current candidate={current['candidate_id']}",
348+
flush=True,
349+
)
350+
deploy_candidate(args.worker_ssh, previous_chunk)
363351
clear_primary_cache()
352+
if baseline is None and iteration == 0:
353+
print(
354+
"[autoresearch] phase=baseline using current candidate",
355+
flush=True,
356+
)
357+
else:
358+
print(
359+
"[autoresearch] phase=strategy-proposal real-gemma",
360+
flush=True,
361+
)
362+
proposed = propose_candidate(
363+
address=args.address,
364+
tokenizer_id=args.tokenizer_id,
365+
program=program,
366+
current=current,
367+
results_text=(
368+
results_path.read_text() if results_path.exists() else ""
369+
),
370+
ledger=json.loads(ledger_path.read_text()),
371+
)
372+
candidate_path.write_text(render_candidate(proposed))
373+
print(
374+
f"[autoresearch] phase=candidate-written "
375+
f"candidate={proposed['candidate_id']} "
376+
f"target={proposed['target_obligation_id']}",
377+
flush=True,
378+
)
379+
deploy_candidate(
380+
args.worker_ssh,
381+
proposed["prefill_compute_chunk_tokens"],
382+
)
383+
clear_primary_cache()
384+
validate_candidate(proposed)
385+
experiment_id = (
386+
f"ar_{int(time.time())}_{iteration}_"
387+
f"{hashlib.sha256(candidate_path.read_bytes()).hexdigest()[:8]}"
388+
)
389+
report_path = reports_dir / f"{experiment_id}.json"
390+
print(
391+
f"[autoresearch] phase=gan-experiment id={experiment_id}",
392+
flush=True,
393+
)
364394
run_id, report, _ = run_gan_experiment(
365395
repo=root,
366396
candidate_path=candidate_path,
@@ -371,6 +401,13 @@ def run_iteration(args, iteration: int) -> dict:
371401
candidate_module = _load_candidate(candidate_path)
372402
result = evaluate(report, candidate_module)
373403
keep = should_keep(result, baseline)
404+
print(
405+
f"[autoresearch] phase=evaluate accepted={result['accepted']} "
406+
f"unresolved={result['proof_obligations_unresolved']} "
407+
f"prefill_s={result['metric_cold_critic_prefill_s']:.3f} "
408+
f"decision={'keep' if keep else 'revert'}",
409+
flush=True,
410+
)
374411
row = {
375412
"timestamp": time.time(),
376413
"experiment_id": experiment_id,
@@ -403,8 +440,15 @@ def run_iteration(args, iteration: int) -> dict:
403440
_restore(state_path, previous_state)
404441
_restore(ledger_path, previous_ledger)
405442
deploy_candidate(args.worker_ssh, previous_chunk)
443+
print("[autoresearch] phase=reverted", flush=True)
444+
else:
445+
print("[autoresearch] phase=kept", flush=True)
406446
return row
407-
except Exception:
447+
except Exception as exc:
448+
print(
449+
f"[autoresearch] phase=failed error={type(exc).__name__}: {exc}",
450+
flush=True,
451+
)
408452
candidate_path.write_bytes(previous_candidate)
409453
_restore(state_path, previous_state)
410454
_restore(ledger_path, previous_ledger)

tests/inference_engine/bench/test_autoresearch_supervisor.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
should_keep,
77
validate_candidate,
88
)
9+
from pathlib import Path
910

1011

1112
def _candidate():
@@ -99,3 +100,18 @@ def test_results_are_append_only_and_best_is_selected(tmp_path):
99100
rows = read_results(path)
100101
assert len(rows) == 2
101102
assert best_kept(rows)["candidate_id"] == "c2"
103+
104+
105+
def test_supervisor_predeploys_before_real_strategy_proposal():
106+
source = (
107+
Path(__file__).resolve().parents[3]
108+
/ "autoresearch"
109+
/ "prefill"
110+
/ "supervisor.py"
111+
).read_text()
112+
body = source[source.index("def run_iteration"):source.index("def main")]
113+
assert body.index("deploy_candidate(args.worker_ssh, previous_chunk)") < (
114+
body.index("proposed = propose_candidate")
115+
)
116+
assert "phase=predeploy-current" in body
117+
assert "phase=strategy-proposal real-gemma" in body

0 commit comments

Comments
 (0)