From b57f8158469dc7b78ea81eb9af143b6e422a556f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Thu, 15 Oct 2026 00:47:57 +0400 Subject: [PATCH] =?UTF-8?q?fix(agent):=20OSError=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D1=82=D0=B2=D0=B5=D1=80=D0=B6=D0=B4=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B8=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8=20?= =?UTF-8?q?=E2=80=94=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3,=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=81=D0=BB=D0=B5=D0=B4=D1=83=D1=8E=D1=89=D0=B5=D0=BC=20cla?= =?UTF-8?q?im=20(M-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- src/agent.py | 6 +++++- tests/test_update.py | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/agent.py b/src/agent.py index 00aef51..4118dfb 100644 --- a/src/agent.py +++ b/src/agent.py @@ -998,7 +998,11 @@ class Updater: """Первый успешный claim новой версии: trial этой версии → ok (запускатель перестаёт ждать отката).""" st = self.state() if st and st.get("state") == "trial" and st.get("to_version") == AGENT_VERSION: - write_update_state(self.state_path, "ok", st.get("from_version"), AGENT_VERSION, st.get("sha256")) + try: + write_update_state(self.state_path, "ok", st.get("from_version"), AGENT_VERSION, st.get("sha256")) + except OSError as e: # диск полон — не падать; trial остался, повтор на следующем claim (M-3) + log("не удалось записать update.json: %s" % e) + return log("обновление до v%d подтверждено" % AGENT_VERSION) def _hint(self, kind: str, msg: str) -> None: diff --git a/tests/test_update.py b/tests/test_update.py index 0c07813..773199c 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -42,6 +42,25 @@ class UpdateStateTest(unittest.TestCase): st = agent.read_update_state(u.state_path) self.assertEqual((st["state"], st["from_version"], st["to_version"], st["sha256"]), ("ok", 4, agent.AGENT_VERSION, "s")) + def test_confirm_write_error_only_logged(self): + """M-3 финального ревью: диск полон в момент подтверждения — агент не падает, подтвердит на следующем claim.""" + u = agent.Updater(None, self.dir.name, 1) + agent.write_update_state(u.state_path, "trial", 4, agent.AGENT_VERSION, "s") + logs = [] + + def full(*a, **kw): + raise OSError(28, "No space left on device") + orig_log, orig_write = agent.log, agent.write_update_state + agent.log, agent.write_update_state = logs.append, full + try: + u.confirm() + finally: + agent.log, agent.write_update_state = orig_log, orig_write + self.assertEqual(u.state()["state"], "trial") + self.assertTrue(any(l.startswith("не удалось записать update.json") for l in logs), logs) + u.confirm() + self.assertEqual(u.state()["state"], "ok") + def test_confirm_ignores_other_states(self): u = agent.Updater(None, self.dir.name, 1) u.confirm()