Skip to content

Commit 5e366b1

Browse files
fluffy314cursoragent
authored andcommitted
fix(autoresearch): elaborate subgoal before OProver
Route an accepted Research Contract without an executable typed node back through certified decomposition so model residency cannot begin against the root directly. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2df7b6a commit 5e366b1

2 files changed

Lines changed: 154 additions & 30 deletions

File tree

autoresearch/prefill/supervisor.py

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,56 @@ def is_nonfatal_semantic_continuation(
16461646
)
16471647

16481648

1649+
def route_contract_to_subgoal_generation(
1650+
checkpoint: OrchestrationCheckpoint,
1651+
) -> bool:
1652+
"""Require a typed elaborated subgoal before any OProver residency request."""
1653+
if (
1654+
checkpoint.proof_state != ProofState.PROOF_SEARCH
1655+
or not checkpoint.research_contract_id
1656+
or checkpoint.proof_plan_id
1657+
or checkpoint.executable_plan_node_id
1658+
):
1659+
return False
1660+
if checkpoint.adapter_status:
1661+
if checkpoint.blocked_reason != (
1662+
"PROOF_ADVISOR_UNAVAILABLE:RESIDENCY_PROCESS_MANAGER_REQUIRED"
1663+
):
1664+
return False
1665+
checkpoint.clear_adapter_blocked(
1666+
"research-contract-awaits-elaborated-subgoal",
1667+
)
1668+
event_id = hashlib.sha256(
1669+
(
1670+
checkpoint.target_obligation_id
1671+
+ checkpoint.research_contract_id
1672+
+ checkpoint.proposition_hash
1673+
).encode()
1674+
).hexdigest()
1675+
if any(
1676+
item.get("event_type") == "RESEARCH_CONTRACT_SUBGOAL_REQUIRED"
1677+
and item.get("event_id") == event_id
1678+
for item in checkpoint.recovery_events
1679+
):
1680+
return False
1681+
checkpoint.transition(
1682+
ProofState.DECOMPOSER,
1683+
"research-contract:generate-strictly-reducing-elaborated-subgoal",
1684+
strategy_reused=True,
1685+
)
1686+
checkpoint.recovery_events.append({
1687+
"event_type": "RESEARCH_CONTRACT_SUBGOAL_REQUIRED",
1688+
"event_id": event_id,
1689+
"target_obligation_id": checkpoint.target_obligation_id,
1690+
"research_contract_id": checkpoint.research_contract_id,
1691+
"selected_strategy_plan_id": checkpoint.selected_strategy_plan_id,
1692+
"proposition_hash": checkpoint.proposition_hash,
1693+
"target_state": ProofState.DECOMPOSER.value,
1694+
"created_at": time.time(),
1695+
})
1696+
return True
1697+
1698+
16491699
def should_resume_downstream(
16501700
checkpoint: OrchestrationCheckpoint | None,
16511701
*,
@@ -2043,6 +2093,23 @@ def run_iteration(args, iteration: int) -> dict:
20432093
orchestration_state_path,
20442094
orchestration_checkpoint,
20452095
)
2096+
if (
2097+
orchestration_checkpoint is not None
2098+
and route_contract_to_subgoal_generation(orchestration_checkpoint)
2099+
):
2100+
save_orchestration_checkpoint(
2101+
orchestration_state_path,
2102+
orchestration_checkpoint,
2103+
)
2104+
print(
2105+
"[proof-live] stage=subgoal-generation "
2106+
f"target={orchestration_checkpoint.target_obligation_id} "
2107+
f"proposition={orchestration_checkpoint.target_statement} "
2108+
f"plan={orchestration_checkpoint.selected_strategy_plan_id} "
2109+
f"contract={orchestration_checkpoint.research_contract_id} "
2110+
"next=DECOMPOSER reason=elaborated-subgoal-required",
2111+
flush=True,
2112+
)
20462113
if (
20472114
orchestration_checkpoint is not None
20482115
and (
@@ -2504,37 +2571,55 @@ def run_iteration(args, iteration: int) -> dict:
25042571
orchestration_checkpoint.proof_state == ProofState.PROOF_SEARCH
25052572
and orchestration_checkpoint.research_contract_id
25062573
):
2507-
# OProver residency is permitted only behind an accepted,
2508-
# elaborated Research Contract. The downstream typed-role GAN
2509-
# remains available for definition/evidence expansion.
2510-
orchestration_checkpoint.adapter_blocked(
2511-
"PROOF_ADVISOR_UNAVAILABLE:"
2512-
"RESIDENCY_PROCESS_MANAGER_REQUIRED",
2513-
status="INTEGRATION_BLOCKED",
2514-
)
2515-
save_orchestration_checkpoint(
2516-
orchestration_state_path,
2574+
if route_contract_to_subgoal_generation(
25172575
orchestration_checkpoint,
2518-
)
2519-
live_status.emit(
2520-
phase="proof_advisor_unavailable",
2521-
role="oprover_advisor",
2522-
state="idle",
2523-
active_obligation_id=(
2524-
orchestration_checkpoint.target_obligation_id
2525-
),
2526-
source="proof_supervisor",
2527-
force=True,
2528-
)
2529-
return {
2530-
"iteration": iteration,
2531-
"research_outcome": "BLOCKED",
2532-
"orchestration_state": "INTEGRATION_BLOCKED",
2533-
"transition_reason": orchestration_checkpoint.blocked_reason,
2534-
"failure_class": "",
2535-
"error": "",
2536-
"inference_started": False,
2537-
}
2576+
):
2577+
save_orchestration_checkpoint(
2578+
orchestration_state_path,
2579+
orchestration_checkpoint,
2580+
)
2581+
print(
2582+
"[proof-live] stage=research-contract "
2583+
f"target={orchestration_checkpoint.target_obligation_id} "
2584+
f"plan={orchestration_checkpoint.selected_strategy_plan_id} "
2585+
f"contract={orchestration_checkpoint.research_contract_id} "
2586+
"accepted=true next=DECOMPOSER "
2587+
"reason=elaborated-subgoal-required",
2588+
flush=True,
2589+
)
2590+
else:
2591+
# OProver residency is permitted only after both an accepted
2592+
# contract and a concrete typed proof-plan node exist.
2593+
orchestration_checkpoint.adapter_blocked(
2594+
"PROOF_ADVISOR_UNAVAILABLE:"
2595+
"RESIDENCY_PROCESS_MANAGER_REQUIRED",
2596+
status="INTEGRATION_BLOCKED",
2597+
)
2598+
save_orchestration_checkpoint(
2599+
orchestration_state_path,
2600+
orchestration_checkpoint,
2601+
)
2602+
live_status.emit(
2603+
phase="proof_advisor_unavailable",
2604+
role="oprover_advisor",
2605+
state="idle",
2606+
active_obligation_id=(
2607+
orchestration_checkpoint.target_obligation_id
2608+
),
2609+
source="proof_supervisor",
2610+
force=True,
2611+
)
2612+
return {
2613+
"iteration": iteration,
2614+
"research_outcome": "BLOCKED",
2615+
"orchestration_state": "INTEGRATION_BLOCKED",
2616+
"transition_reason": (
2617+
orchestration_checkpoint.blocked_reason
2618+
),
2619+
"failure_class": "",
2620+
"error": "",
2621+
"inference_started": False,
2622+
}
25382623
experiment_id = (
25392624
f"ar_{int(time.time())}_{iteration}_"
25402625
f"{hashlib.sha256(candidate_path.read_bytes()).hexdigest()[:8]}"

tests/inference_engine/bench/test_autoresearch_supervisor.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
read_results,
4848
repair_candidate_schema,
4949
render_candidate,
50+
route_contract_to_subgoal_generation,
5051
run_supervisor_iterations,
5152
select_novel_candidate,
5253
should_resume_downstream,
@@ -61,6 +62,44 @@
6162
from pathlib import Path
6263

6364

65+
def test_contract_requires_elaborated_subgoal_before_oprover():
66+
checkpoint = OrchestrationCheckpoint(
67+
state=ProofState.PROOF_SEARCH.value,
68+
current_role="proof_search",
69+
target_obligation_id="RH-C0-root",
70+
target_statement="RiemannHypothesis",
71+
proposition_hash="p" * 64,
72+
selected_strategy_plan_id="SP-root",
73+
research_contract_id="RC-root",
74+
adapter_status="INTEGRATION_BLOCKED",
75+
blocked_reason=(
76+
"PROOF_ADVISOR_UNAVAILABLE:"
77+
"RESIDENCY_PROCESS_MANAGER_REQUIRED"
78+
),
79+
)
80+
assert route_contract_to_subgoal_generation(checkpoint)
81+
assert checkpoint.proof_state == ProofState.DECOMPOSER
82+
assert checkpoint.adapter_status == ""
83+
assert checkpoint.recovery_events[-1]["event_type"] == (
84+
"RESEARCH_CONTRACT_SUBGOAL_REQUIRED"
85+
)
86+
assert not route_contract_to_subgoal_generation(checkpoint)
87+
88+
89+
def test_contract_with_executable_subgoal_does_not_backjump():
90+
checkpoint = OrchestrationCheckpoint(
91+
state=ProofState.PROOF_SEARCH.value,
92+
current_role="proof_search",
93+
target_obligation_id="RH-C0-root",
94+
proposition_hash="p" * 64,
95+
research_contract_id="RC-root",
96+
proof_plan_id="PP-child",
97+
executable_plan_node_id="L1",
98+
)
99+
assert not route_contract_to_subgoal_generation(checkpoint)
100+
assert checkpoint.proof_state == ProofState.PROOF_SEARCH
101+
102+
64103
def test_live_status_atomic_transitions_and_permissions(tmp_path):
65104
path = tmp_path / "proof_live_status.json"
66105
status = AtomicLiveStatus(

0 commit comments

Comments
 (0)