From 8f0c255df2d5cb0300b76ff3b38a503d1429d18e Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Thu, 5 Nov 2026 09:01:41 +0800 Subject: [PATCH] fix(heartbeat): qualify complete native context route budget Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- .../contracts/interface-budget-contract.md | 31 +++++++++++++++++++ loopx/control_plane/heartbeat/budget.py | 9 +++--- tests/control_plane/test_cli_output_budget.py | 6 ++-- .../test_heartbeat_agent_input.py | 2 +- .../test_heartbeat_envelope_transport.py | 8 ++--- .../test_heartbeat_prompt_support.py | 4 +-- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/docs/reference/contracts/interface-budget-contract.md b/docs/reference/contracts/interface-budget-contract.md index 2484f1bb86..0060122242 100644 --- a/docs/reference/contracts/interface-budget-contract.md +++ b/docs/reference/contracts/interface-budget-contract.md @@ -810,3 +810,34 @@ characters once. Missing clauses, unrelated surfaces and later new→new growth retain ordinary gates. This is cost attribution, not admission logic or proof of semantic equivalence. The PR's clause review and current-path validation remain necessary; deleting an obligation cannot earn this allowance. + +### Thin native context route allowance + +The complete real-CLI workload (320-character scope, five capabilities and an +explicit CLI route) now emits 4,999 normalized body characters on macOS with the +default native context routes. The earlier route qualification measured 4,851; the +current 4,900 ceiling therefore marks a supported combination over budget. Retain the +complete commands and instructions and raise only the thin presentation +allowance to 5,100, leaving 101 characters of headroom. The unchanged negative +case adds 48 characters to the CLI route, repeated four times, and still fails +with an overflow at 5,191. The original 4,900 failure remains historical evidence. + +Matched base/head rendering on one frozen fixture preserves every body byte in +ordinary thin, explicit context-off, captured TurnEnvelope, brief, compact and +full modes. The supported thin body remains 5,347 actual characters / 5,351 +UTF-8 bytes; this does not reduce model input or establish token, latency or +cost savings. The separate 400-character captured-envelope and 640-character +Reward Memory allowances remain fixed. The no-memory captured-envelope ceiling +therefore becomes 5,500. Other mode limits, JSON/output/key/line guards, +execution quotas, host hard limits and frozen qualification thresholds stay +unchanged; already-over-budget brief/compact/full workloads remain failures. + +完整真实 CLI 负载(320 字符 scope、五项能力及显式 CLI 路径)在 macOS 默认原生上下文 +路由下为 4,999 个归一化正文字符;此前路径资格化为 4,851,现有 4,900 +展示上限因此将受支持组合标为超限。保留完整命令和指令,仅将 thin 展示预算调至 5,100, +余量 101 字符。原负例仍将 CLI 路径增加 48 字符、重复四次,在 5,191 时报告超限; +原 4,900 上限失败保留。单一冻结夹具的 base/head 各模式正文逐字节相同,受支持 +thin 仍为实际 5,347 字符/5,351 UTF-8 字节,不据此宣称输入、token、延迟或费用 +下降。可选 envelope 的 400 和 Reward Memory 的 640 字符余量不变;无 memory 的 +envelope 上限随 thin 基础预算变为 5,500。其余模式、JSON/输出/键数/行数、执行 +额度、宿主硬限制及冻结门槛不变;已超限的 brief/compact/full 场景仍保持失败。 diff --git a/loopx/control_plane/heartbeat/budget.py b/loopx/control_plane/heartbeat/budget.py index fc261fd7d2..06e584224c 100644 --- a/loopx/control_plane/heartbeat/budget.py +++ b/loopx/control_plane/heartbeat/budget.py @@ -23,10 +23,11 @@ # The same generic CLI + 320-char scope with explicit runtime also needs # 5,715 chars; retain those routes instead of shortening the instructions. "brief": 5_800, - # Full runtime capability flags plus an explicit CLI route and 320-char - # scope emit 4,851 normalized chars with unchanged guidance. Keep that - # supported combination; this is not a transport or execution limit. - "thin": 4_900, + # Default native context routes bring the complete capability/CLI-route + # fixture with a 320-char scope from 4,851 to 4,999 normalized chars. + # Retain the full instructions and 101 chars of presentation headroom; + # the unchanged oversized-route case still exceeds this allowance. + "thin": 5_100, "visible_goal": 4_000, } NATIVE_GOAL_HOST_MAX_CHARS = INTERFACE_BUDGET_CHARS["visible_goal"] diff --git a/tests/control_plane/test_cli_output_budget.py b/tests/control_plane/test_cli_output_budget.py index a6a35c3c4c..2e4806d620 100644 --- a/tests/control_plane/test_cli_output_budget.py +++ b/tests/control_plane/test_cli_output_budget.py @@ -1776,7 +1776,7 @@ def test_thin_json_budget_retains_full_supported_scope(tmp_path: Path) -> None: ) payload = measurement["payload"] assert scope in payload["task_body"] - assert payload["interface_budget"]["max_chars"] == 4900 + assert payload["interface_budget"]["max_chars"] == 5100 assert payload["interface_budget"]["within_budget"] is True assert "refresh-state --goal-outcome-update-json" in payload["task_body"] assert "Local outcomes never replace root continuation, budget or stop criteria." in payload["task_body"] @@ -1816,8 +1816,8 @@ def test_thin_budget_covers_complete_capability_and_cli_routes( # Preserve the historical 4,500-character failure as a characterized # input; the allowance changes, not the complete emitted instructions. assert budget["budget_char_count"] > 4500 - assert budget["max_chars"] == 4900 - assert budget["within_budget"] is within_budget + assert budget["max_chars"] == 5100 + assert budget["within_budget"] is within_budget, budget def test_brief_budget_retains_full_commands_on_real_long_paths() -> None: diff --git a/tests/control_plane/test_heartbeat_agent_input.py b/tests/control_plane/test_heartbeat_agent_input.py index 8782181612..8e158e23c1 100644 --- a/tests/control_plane/test_heartbeat_agent_input.py +++ b/tests/control_plane/test_heartbeat_agent_input.py @@ -65,7 +65,7 @@ def test_thin_cli_preserves_readable_admission_and_authority_with_host_scope(tmp packet = json.loads(subprocess.check_output(command, text=True)) assert packet["ok"] is True budget = packet["interface_budget"] - assert budget["max_chars"] == 4900 + assert budget["max_chars"] == 5100 assert budget["budget_char_count"] <= budget["max_chars"] assert budget["within_budget"] is True body = packet["task_body"] diff --git a/tests/control_plane/test_heartbeat_envelope_transport.py b/tests/control_plane/test_heartbeat_envelope_transport.py index 6905ec9680..e19efdb46f 100644 --- a/tests/control_plane/test_heartbeat_envelope_transport.py +++ b/tests/control_plane/test_heartbeat_envelope_transport.py @@ -95,13 +95,13 @@ def test_capture_preserves_full_dispatcher_and_envelope_needs_explicit_opt_in(tm no_memory = dict(args, reward_memory_enabled=False) ordinary = build_heartbeat_prompt(**no_memory) captured_only = build_heartbeat_prompt(**no_memory, decision_output_root=tmp_path) - assert ordinary['interface_budget']['max_chars'] == 4_900 - assert captured_only['interface_budget']['max_chars'] == 4_900 + assert ordinary['interface_budget']['max_chars'] == 5_100 + assert captured_only['interface_budget']['max_chars'] == 5_100 oversized = build_heartbeat_prompt( **no_memory, decision_output_root=tmp_path, turn_envelope=True, agent_scopes=[letter * 320 for letter in 'stuv'], ) - assert oversized['interface_budget']['max_chars'] == 5_300 + assert oversized['interface_budget']['max_chars'] == 5_500 assert oversized['interface_budget']['within_budget'] is False for overrides in (dict(turn_instance_id=None), dict(thin=False, full=True), dict(runtime_profile='codex_app_ssh_goal')): @@ -176,7 +176,7 @@ def test_bound_captured_prompt_fits_budget_without_reward_memory( assert '--reward-memory-reflection-json' not in body assert str(runtime) in body and str(capture) in body assert payload['turn_instance_id'] == TURN_ID - assert payload['interface_budget']['max_chars'] == 5_300 + assert payload['interface_budget']['max_chars'] == 5_500 assert payload['interface_budget']['within_budget'], payload['interface_budget'] assert len(result.stdout) <= 5_400 # Shipped Agent JSON, not generator metadata. assert 'using inline ACK argv' in body diff --git a/tests/control_plane/test_heartbeat_prompt_support.py b/tests/control_plane/test_heartbeat_prompt_support.py index a31d282301..a074c9dea1 100644 --- a/tests/control_plane/test_heartbeat_prompt_support.py +++ b/tests/control_plane/test_heartbeat_prompt_support.py @@ -98,7 +98,7 @@ def test_native_profile_long_routes_retain_one_complete_settlement_contract() -> @pytest.mark.parametrize("mode,limit", [ ("full", 13100), ("compact", 8000), ("brief", 5800), - ("thin", 4900), ("visible_goal", 4000), + ("thin", 5100), ("visible_goal", 4000), ]) def test_prompt_body_limit_remains_independent_of_json_envelope(mode: str, limit: int) -> None: for size in (limit, limit + 1): @@ -356,7 +356,7 @@ def test_brief_diagnostics_keep_only_the_selected_prompt_command() -> None: @pytest.mark.parametrize( ("mode", "base_budget"), - [("full", 13100), ("compact", 8000), ("brief", 5800), ("thin", 4900)], + [("full", 13100), ("compact", 8000), ("brief", 5800), ("thin", 5100)], ) @pytest.mark.parametrize("scope_chars", [0, 320]) @pytest.mark.parametrize("runtime_profile", ["codex_app_heartbeat", "generic_cli"])