diff --git a/docs/heartbeat-automation-prompt.md b/docs/heartbeat-automation-prompt.md index b2154dd30a..3095bbeafc 100644 --- a/docs/heartbeat-automation-prompt.md +++ b/docs/heartbeat-automation-prompt.md @@ -73,6 +73,14 @@ static refresh/spend sequence: after validated work it follows the current compatibility, not as a stale fallback. Todo acceptance alone is not Turn settlement or terminal vision closure. The brief base budget is 4,800 characters; reward-memory headroom remains separate. +Markdown prints a complete guard command once when the successful task body +already contains that exact command as a whole line. Generator Inputs then +points to the body; JSON fields remain complete. Missing, different, partial or +failed bodies retain the complete diagnostic command. + +成功正文已按完整行包含同一 guard 命令时,Markdown 诊断区指向正文,避免重复长命令; +JSON 字段保留全文。正文缺失、不同、仅匹配前缀或生成失败时,诊断区仍打印完整命令。 + Brief 与 thin 共用完整执行义务路径;full、compact、brief 均移除固定结算配方,而不是 删除结算义务。真实 App preflight、registry scope、完整 guard 和静态安全规则 均保留;结算顺序与身份以本轮动态 contract 为准,vision replan 不由历史成功清账。 diff --git a/loopx/control_plane/heartbeat/task_body.py b/loopx/control_plane/heartbeat/task_body.py index ecbe38c5cb..f9f24202d4 100644 --- a/loopx/control_plane/heartbeat/task_body.py +++ b/loopx/control_plane/heartbeat/task_body.py @@ -781,9 +781,22 @@ def render_heartbeat_generator_inputs_markdown(payload: dict[str, Any]) -> str: "- pr_review_pre_quota_command: " f"`{payload['pr_review_pre_quota_command']}`" ) + guard_command = payload.get("quota_guard_command") + task_body = payload.get("task_body") + # The copyable body already owns this exact command. Keep one complete + # spelling in Markdown; failed/partial bodies still need the diagnostic. + guard_in_body = ( + payload.get("ok") is not False + and isinstance(guard_command, str) + and bool(guard_command.strip()) + and isinstance(task_body, str) + and guard_command in task_body.splitlines() + ) lines.extend( [ - f"- quota_guard_command: `{payload.get('quota_guard_command')}`", + "- quota_guard_command: shown verbatim in task body" + if guard_in_body + else f"- quota_guard_command: `{guard_command}`", f"- quota_spend_command: `{payload.get('quota_spend_command')}`", f"- cli_preflight: `{payload.get('cli_preflight')}`", "- interface_budget: " diff --git a/tests/control_plane/test_heartbeat_prompt_support.py b/tests/control_plane/test_heartbeat_prompt_support.py index 0ee07b047d..0e0885ee2a 100644 --- a/tests/control_plane/test_heartbeat_prompt_support.py +++ b/tests/control_plane/test_heartbeat_prompt_support.py @@ -272,6 +272,27 @@ def test_thin_markdown_diagnostics_only_show_the_selected_prompt_command() -> No assert "- expanded_prompt_command:" not in rendered assert "- compact_prompt_command:" not in rendered assert "- brief_prompt_command:" not in rendered + assert payload["quota_guard_command"] in payload["task_body"].splitlines() + assert rendered.count(payload["quota_guard_command"]) == 1 + assert "- quota_guard_command: shown verbatim in task body" in rendered + + +@pytest.mark.parametrize("body_kind", ["missing", "prefix", "different", "error"]) +def test_markdown_keeps_guard_diagnostic_without_a_successful_exact_body_command(body_kind) -> None: + command = "loopx quota should-run --goal-id fixture" + body = { + "missing": "", + "prefix": command + " --todo-id another-todo", + "different": "loopx quota should-run --goal-id another-goal", + "error": command, + }[body_kind] + rendered = render_heartbeat_generator_inputs_markdown({ + "ok": body_kind != "error", + "task_body": body, + "quota_guard_command": command, + }) + assert f"- quota_guard_command: `{command}`" in rendered + assert "shown verbatim in task body" not in rendered @pytest.mark.parametrize("resolved", ["same", "different", None]) @@ -306,8 +327,10 @@ def test_markdown_diagnostics_keep_available_prequota_commands(review_enabled) - ) rendered = render_heartbeat_prompt_markdown(payload) assert payload["task_body"] in rendered - for key in ("thin_prompt_command", "quota_guard_command", "quota_spend_command"): + for key in ("thin_prompt_command", "quota_spend_command"): assert f"- {key}: `{payload[key]}`" in rendered + assert payload["quota_guard_command"] in payload["task_body"].splitlines() + assert rendered.count(payload["quota_guard_command"]) == 1 if review_enabled: assert "heartbeat-prequota" in payload["pr_review_pre_quota_command"] assert f"- pr_review_pre_quota_command: `{payload['pr_review_pre_quota_command']}`" in rendered