From 8c719c7e6287aa7ec6208519cbea83a48e9739b6 Mon Sep 17 00:00:00 2001 From: host Date: Thu, 29 Oct 2026 15:31:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=AD=E7=82=B9=E9=95=9C=E5=83=8F=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=A0=87=E7=AD=BE=E5=9B=9E=E8=90=BD=EF=BC=9Ahost-stat?= =?UTF-8?q?e=20=E6=9D=A1=E7=9B=AE=E5=86=99=20status=20=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=20goal=5Fstatus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 生产实弹:极小 goal 任务的 timeline 里 checkpoint goal_status 为 None——host.py 的任务条目只有 status(goal-running/goal-met), 没有 goal_status 键,镜像原样读 goal_status 永远是空。修法: entry.get('goal_status') or entry.get('status')。轮次、thread_id、 state_sha 等关键字段不受影响(熔断只看轮次),纯标签 fidelity 修复;单测加 status-only 条目镜像断言。 --- cloud/tests/test_p0_three.py | 18 ++++++++++++++++++ cloud/worker.py | 9 +++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/cloud/tests/test_p0_three.py b/cloud/tests/test_p0_three.py index 4dcd061..6778838 100644 --- a/cloud/tests/test_p0_three.py +++ b/cloud/tests/test_p0_three.py @@ -240,6 +240,24 @@ class CheckpointMirrorTestCase(unittest.TestCase): conn.close() self.assertEqual(rows, [(1, "round"), (2, "round")]) + def test_mirror_falls_back_to_status_label(self): + # host-state 条目写的是 status 不是 goal_status:实弹里 + # 镜像到的 goal_status 全是 None,修法是取 status 回落。 + with open(self.state_path, "w", encoding="utf-8") as fh: + json.dump({"version": 1, "tasks": {"T1": { + "goal_rounds_done": 2, "thread_id": "th2", + "status": "goal-met", + "goal_last_verify": ""}}}, fh) + self.assertEqual(self.worker._mirror_checkpoint_once(self.task), 2) + conn = sqlite3.connect(self.db_path) + try: + row = conn.execute( + "SELECT round_no, thread_id, goal_status" + " FROM task_checkpoints WHERE task_id = 'T1'").fetchone() + finally: + conn.close() + self.assertEqual(row, (2, "th2", "goal-met")) + def test_rebuild_without_checkpoint_is_false(self): with open(self.state_path, "w", encoding="utf-8") as fh: json.dump({"version": 1, "tasks": {}}, fh) diff --git a/cloud/worker.py b/cloud/worker.py index d704ac9..1bf81da 100644 --- a/cloud/worker.py +++ b/cloud/worker.py @@ -1104,6 +1104,11 @@ class Worker: if not isinstance(entry, dict): return -1 rounds = int(entry.get("goal_rounds_done") or 0) + # host-state 条目写的是 status(goal-running/goal-met…), + # 不是 goal_status:实弹里镜像到的 goal_status 全是 + # None——取 status 作回落,标签才不是空的(轮次与 + # thread_id 等关键字段不受影响,熔断只看轮次)。 + goal_status = entry.get("goal_status") or entry.get("status") state_sha = hashlib.sha256( json.dumps(entry, sort_keys=True, default=str).encode("utf-8")).hexdigest() @@ -1121,7 +1126,7 @@ class Worker: " verify_out = ?, created_at = ?" " WHERE task_id = ? AND round_no = ?", (entry.get("thread_id"), - entry.get("goal_status"), + goal_status, state_sha, (entry.get("goal_last_verify") or "")[:500], time.time(), task["id"], rounds)) @@ -1131,7 +1136,7 @@ class Worker: " thread_id, goal_status, state_sha, verify_out," " created_at) VALUES(?, ?, ?, ?, ?, ?, ?)", (task["id"], rounds, entry.get("thread_id"), - entry.get("goal_status"), state_sha, + goal_status, state_sha, (entry.get("goal_last_verify") or "")[:500], time.time())) self._import_host_steps(conn, task, state_path)