v2 rehearsal: FLAG-3 order note-before-notice on first-turn co-pending (fix effective order, pin with test)

This commit is contained in:
host committed 2026-11-05 02:45:09 +00:00
1 parent 6a70775ad9
commit adc2a02f6c
2 files changed
+40 -9

No files matched your search

+27
View File
@@ -504,6 +504,33 @@ class HostLoopTestCase(unittest.TestCase):
self.assertIn("new goal", prompts[0])
self.assertIn("旧目标", prompts[0])
def test_first_turn_both_pending_note_before_notice(self):
# FLAG-3 定序(v2 演练决定):首轮断点备注与改 goal 通知
# 同 pending 时,模型可见顺序为备注在前、通知在后。
# 注意代码里两次 prepend 的执行顺序与可见顺序相反
# (先贴通知、再贴备注),本测试钉住的是可见顺序,
# 而非执行顺序。
task = self._task()
self._write_signal(1, "new goal")
prompts = []
script = [("completed", "目标已达成", None)]
fake = _fake_turn_script(prompts, script)
note = ("[审计推回包(第 1 轮)]\n"
"- [execution_failed] 证据:boom detail")
with mock.patch.object(host_mod, "run_task_turn", fake):
result = host_mod.run_goal_loop(
SimpleNamespace(), self.state, self.state_path, task,
"old goal", None, 0, None, None, None, cfg=None,
resume_note=note)
self.assertTrue(result["ok"])
self.assertEqual(result["rounds_done"], 1)
self.assertEqual(len(prompts), 1)
first = prompts[0]
self.assertTrue(first.startswith(note))
self.assertLess(first.index(note), first.index("目标已更新"))
self.assertIn("new goal", first)
self.assertIn("作废", first)
if __name__ == "__main__":
unittest.main()
+13 -9
View File
@@ -2915,21 +2915,25 @@ def run_goal_loop(server, state, state_path, task, goal_text, verify,
f"目标:{goal_text}\n"
f"验收命令:{verify_text}\n"
f"上一轮验收输出:\n{last_verify}")
# FLAG-3 定序(v2 演练决定):首轮两者同 pending 时,
# 模型可见顺序为断点备注在前、改 goal 通知在后、再是
# 本轮任务提示。注意两次 prepend 的执行顺序与可见顺序
# 相反:先贴通知、再贴备注,最终才是备注在前。v1 注释
# 声称“先见备注”但代码实际产生通知在前,v2 在此修正,
# 并由 test_goal_live_update 的共 pending 测试钉住。
# 影响面仅首轮共 pending 时;之后轮次备注块是 no-op,
# 通知块行为不变。
if pending_goal_notice is not None:
# 本轮提示显式写出旧 goal → 新 goal;通知只用一次,
# 下一轮提示是重新构造的,不重复贴。
prompt = pending_goal_notice + "\n\n" + prompt
pending_goal_notice = None
# N-12:断点备注只贴第一轮 prompt(见 _first_turn 注释),
# 绝不写回 goal_text——task["goal"] 在循环开始时已按原
# goal_text 落盘,备注只是本次续跑的展示前缀。
if _first_turn and resume_note:
prompt = "%s\n\n%s" % (resume_note, prompt)
_first_turn = False
# 演练注 FLAG:与上同锚点——运行中改 goal 的旧→新通知
# 与 N-12 断点备注同属 prompt 前缀;两段独立 flag,
# 并集保留(备注在前、改 goal 通知在后);若首轮两者
# 同 pending,模型先见备注后见改 goal 通知,顺序待定。
if pending_goal_notice is not None:
# 本轮提示显式写出旧 goal → 新 goal;通知只用一次,
# 下一轮提示是重新构造的,不重复贴。
prompt = pending_goal_notice + "\n\n" + prompt
pending_goal_notice = None
try:
result = run_task_turn(server, state, task, prompt,
model, effort, sandbox, timeout=timeout,