Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,20 @@ through an authorized controller read route. The destination file must be new,
outside the artifact and native bank, and installed at the Host's existing
phase-file route before starting its ordinary entry command.

Planning input no longer projects the Host's deadline, remaining time or
execution reserve to the model. The original task-planning packet is preserved;
no replacement Host runtime guidance is added to planning or execution wakes.
The Host still enforces its finite budget and retains clocks in runtime state
and receipts. Task-defined time constraints and evaluation cooldowns are unchanged.

This is a planning prompt default change. Execution inputs, scoring, acceptance,
TurnEnvelope and terminal authority are unchanged. Old session archives may still
contain historical deadline messages: this change does not rewrite or neutralize
those messages. An authorized continuation must address stale context at its
restore boundary, and a terminal Goal still requires explicit resume. This PR
prevents new planning-clock injection; it does not qualify old-archive recovery
or claim improved model behavior or scores.

The sealed deadline and native capture timestamp determine the remainder; the
receiver recomputes it. A point with two hours remaining keeps that duration
after an eight-hour offline gap. It does not reuse the old absolute epoch or
Expand Down
25 changes: 3 additions & 22 deletions benchmark/runtime/planning.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,21 @@
import json
import math
import subprocess
import time
from pathlib import Path


def render_planning_prompt(packet: dict, env: dict[str, str], *, execution_reserve_seconds: int) -> str:
"""Project caller-owned clocks without changing the product planning packet."""
def render_planning_prompt(packet: dict, env: dict[str, str]) -> str:
"""Preserve the task packet without projecting the Host's execution clock."""
if "LOOPX_PLANNING_TIMEOUT_SEC" in env:
raise ValueError(
"Remove LOOPX_PLANNING_TIMEOUT_SEC; planning uses LOOPX_PHASE_DEADLINE_EPOCH"
)
window = []
key = "LOOPX_PHASE_DEADLINE_EPOCH"
if key in env:
value = float(env[key])
if not math.isfinite(value) or value <= 0:
raise ValueError(f"{key} must be finite and positive")
observed = time.time()
window.extend([
f"Absolute phase deadline: {value} Unix UTC seconds.",
f"Remaining phase time at observation {observed}: {max(0, value - observed):.1f} seconds.",
f"Existing execution reserve: {execution_reserve_seconds} seconds. "
f"Observed work window before that reserve: {max(0, value - observed - execution_reserve_seconds):.1f} seconds.",
"This shared window includes planning and subsequent execution; "
"runtime startup and settlement reserves also consume it.",
])
prefix = "$loopx\n\n"
if window:
prefix += "Host execution window:\n" + "\n".join(window) + "\n"
prefix += (
"Use these observations to size the plan and its validation. They age "
"as work proceeds; the runtime still enforces its original limits. "
"They grant no extra time or authority and do not relax task acceptance.\n\n"
)
return prefix + "Host-supplied planning checkpoint:\n" + json.dumps(packet, ensure_ascii=False)
return "$loopx\n\nHost-supplied planning checkpoint:\n" + json.dumps(packet, ensure_ascii=False)


def task_plan_packet(env: dict[str, str], cli: list[str]) -> dict:
Expand Down
3 changes: 1 addition & 2 deletions benchmark/runtime/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,7 @@ def run_once(env: dict[str, str]) -> dict:
from benchmark.runtime.planning import render_planning_prompt, task_plan_packet

planning_before = task_plan_packet(env, loopx_command(env))
body = render_planning_prompt(planning_before, env,
execution_reserve_seconds=PHASE_WORK_RESERVE_SECONDS)
body = render_planning_prompt(planning_before, env)
(wake / "planning-input.json").write_text(body, encoding="utf-8")
(wake / "planning-schema.json").write_text(json.dumps(planning_before["result_schema"]))
elif execution.mode in {"heartbeat", "loopx-goal"}:
Expand Down
9 changes: 9 additions & 0 deletions benchmark/tests/test_native_checkpoint_handoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,11 +700,20 @@ def response(payload, index, message):
LOOPX_CODEX_HOME=str(tmp_path / "worker-home"), LOOPX_SHARED_SKILLS=str(skills),
MODEL_NAME="fixture", REASONING_EFFORT="high", OPENAI_BASE_URL=base_url,
OPENAI_API_KEY="synthetic-local-only", LOOPX_CODEX_TURN_TIMEOUT_SEC="60")
deadline = str(time.time() + 600)
env["LOOPX_PHASE_DEADLINE_EPOCH"] = deadline
if capture != "off":
env["LOOPX_CHECKPOINT_REQUEST"] = str(request)
result = run_once(env)
assert result["ok"] and not result["timed_out"], result
assert _heartbeat_receipt_count(runtime, TURN_ID) == 1
# Checkpoint preloading keeps the existing heartbeat contract without
# injecting a Host countdown or runtime guidance.
worker_input = next(t for t in texts(requests[1]) if "quota should-run" in t and "```sh" in t)
assert deadline not in worker_input
assert "Absolute phase deadline" not in worker_input
assert "Current wake execution limit" not in worker_input
assert "The Host enforces runtime limits externally" not in worker_input
if capture == "off":
assert "checkpoint_handoffs" not in result
assert "--decision-handoff-socket" not in guards[0]
Expand Down
6 changes: 3 additions & 3 deletions benchmark/tests/test_resume_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@ def log_message(self, *args):
assert len(requests) == 2
history = json.dumps(requests[1]["input"])
assert "planning-input" in history and "planning-ack" in history
assert "Host execution window" in history
assert "Existing execution reserve: 160 seconds" in history
assert env["LOOPX_PHASE_DEADLINE_EPOCH"] in history
assert "Host execution window" not in history
assert "Existing execution reserve" not in history
assert env["LOOPX_PHASE_DEADLINE_EPOCH"] not in history
assert "Current Todo input." in history
assert len(list((tmp_path / "logs/sessions").rglob("*.jsonl"))) == 1
finally:
Expand Down
71 changes: 50 additions & 21 deletions benchmark/tests/test_task_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def test_prose_or_fabricated_todo_does_not_qualify_planning(planning_env):
)


def test_planner_receives_existing_phase_clock_without_changing_task_identity(planning_env):
def test_planner_keeps_host_clock_out_of_model_input_and_preserves_task_identity(planning_env):
from benchmark.runtime.planning import task_plan_packet
from benchmark.runtime.worker import loopx_command

Expand All @@ -208,34 +208,27 @@ def test_planner_receives_existing_phase_clock_without_changing_task_identity(pl
receipt = run_once(env)
assert receipt["ok"] and receipt["planning"]["state_readback_verified"]
body = next(Path(env["LOOPX_WAKE_LOG_DIR"]).glob("*/planning-input.json")).read_text()
assert deadline in body
assert "Host execution window" in body
assert "Existing execution reserve: 160 seconds" in body
assert deadline not in body
assert "Host execution window" not in body
assert "Existing execution reserve" not in body
packet = json.loads(body.split("Host-supplied planning checkpoint:\n", 1)[1])
assert packet == before
assert receipt["planning"]["input_digest"] == before["input_digest"]
assert env["LOOPX_PHASE_DEADLINE_EPOCH"] == deadline
assert not list(Path(env["LOOPX_PROJECT"]).iterdir())


def test_planning_window_uses_one_phase_deadline_and_preserves_packet(monkeypatch):
from benchmark.runtime import planning
def test_planning_input_is_clock_independent_but_preserves_task_time_constraints():
from benchmark.runtime.planning import render_planning_prompt

monkeypatch.setattr(planning, "time", SimpleNamespace(time=lambda: 1000.0))
packet = {"input_digest": "unchanged", "text": "保留原始任务"}
legacy = "$loopx\n\nHost-supplied planning checkpoint:\n" + json.dumps(packet, ensure_ascii=False)
assert planning.render_planning_prompt(packet, {}, execution_reserve_seconds=160) == legacy
env = {"LOOPX_PHASE_DEADLINE_EPOCH": "1600"}
body = planning.render_planning_prompt(packet, env, execution_reserve_seconds=160)
assert "Absolute phase deadline: 1600.0 Unix UTC seconds" in body
assert "Remaining phase time at observation 1000.0: 600.0 seconds" in body
assert "Observed work window before that reserve: 440.0 seconds" in body
assert "Planning invocation limit" not in body
packet = {"input_digest": "unchanged", "text": "Task constraint: inference under 30 seconds."}
body = render_planning_prompt(packet, {})
for deadline in ["100", "1600", "9999999999"]:
env = {"LOOPX_PHASE_DEADLINE_EPOCH": deadline}
assert render_planning_prompt(packet, env) == body
assert env == {"LOOPX_PHASE_DEADLINE_EPOCH": deadline}
assert json.loads(body.split("Host-supplied planning checkpoint:\n", 1)[1]) == packet
monkeypatch.setattr(planning, "time", SimpleNamespace(time=lambda: 1700.0))
expired = planning.render_planning_prompt(packet, env, execution_reserve_seconds=160)
assert "Remaining phase time at observation 1700.0: 0.0 seconds" in expired
assert env == {"LOOPX_PHASE_DEADLINE_EPOCH": "1600"}
assert body == "$loopx\n\nHost-supplied planning checkpoint:\n" + json.dumps(packet, ensure_ascii=False)


@pytest.mark.parametrize("value", ["nan", "inf", "-inf", "0", "-1", "not-a-clock"])
Expand All @@ -244,7 +237,7 @@ def test_planning_window_rejects_invalid_host_clock(value):

with pytest.raises(ValueError):
render_planning_prompt({"input_digest": "unchanged"},
{"LOOPX_PHASE_DEADLINE_EPOCH": value}, execution_reserve_seconds=160)
{"LOOPX_PHASE_DEADLINE_EPOCH": value})


def test_retired_planning_limit_fails_before_host_invocation(planning_env):
Expand Down Expand Up @@ -747,3 +740,39 @@ async def no_pending(**kwargs):
assert profile.get("stride_strategy", "off") == (strategy or "off")
assert agent._replan_receipt() == {field: value, **({"stride_strategy": strategy}
if strategy is not None else {})}


@pytest.mark.parametrize("context", ["fresh", "resume"])
def test_execute_wake_keeps_host_clocks_out_of_fresh_and_resumed_input(planning_env, context):
"""Exercise the real worker/heartbeat CLI and capture its model transport input."""
env = planning_env | {"LOOPX_ITERATION_CONTEXT": context}
assert run_once(env)["ok"]
binary = Path(env["CODEX_BIN"])
binary.write_text(
f"#!{sys.executable}\n"
"import json, os, pathlib, sys\n"
"pathlib.Path(os.environ['CODEX_HOME'], 'execute-input.txt').write_text(sys.stdin.read())\n"
"print(json.dumps({'type': 'thread.started', 'thread_id': 'planning-fixture-session'}))\n"
)
before = Path(env["LOOPX_REGISTRY"]).with_name("state.md").read_bytes()
old_deadline = env["LOOPX_PHASE_DEADLINE_EPOCH"]
for offset in [900, 500]:
deadline = str(time.time() + offset)
current = env | {"LOOPX_TASK_STAGE": "execute",
"LOOPX_PHASE_DEADLINE_EPOCH": deadline,
"LOOPX_CODEX_TURN_TIMEOUT_SEC": "120"}
receipt = run_once(current)
assert receipt["ok"]
body = (Path(env["LOOPX_CODEX_HOME"]) / "execute-input.txt").read_text()
assert deadline not in body
assert "Absolute phase deadline" not in body
assert old_deadline not in body
assert "Current wake execution limit" not in body
assert "Existing execution reserve" not in body
assert "The Host enforces runtime limits externally" not in body
assert "heartbeat-prompt" in body or "quota" in body
assert receipt["session"]["action"] == ("resume" if context == "resume" else "start_new")
assert "turn_envelope" not in receipt
assert current["LOOPX_PHASE_DEADLINE_EPOCH"] == deadline
# Runtime clocks remain internal and never change task/completion authority.
assert Path(env["LOOPX_REGISTRY"]).with_name("state.md").read_bytes() == before
Loading