From bde81fe0b45ffce75f754ed1eb397b98b80531b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 20:50:27 +0000 Subject: [PATCH 1/2] Initial plan From 6c9e0b374c590482f897a83aec4a7d1d0d54c85f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 20:54:28 +0000 Subject: [PATCH 2/2] fix: log warning instead of silently passing on KeyError in illustration progress update Agent-Logs-Url: https://github.com/CyberSecDef/NovelForge/sessions/2af5748d-8349-42e2-8634-75f051258adf Co-authored-by: CyberSecDef <17597068+CyberSecDef@users.noreply.github.com> --- novelforge/routes/export.py | 5 +++- tests/test_illustration_job.py | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/novelforge/routes/export.py b/novelforge/routes/export.py index e101cf3..710fba6 100644 --- a/novelforge/routes/export.py +++ b/novelforge/routes/export.py @@ -571,7 +571,10 @@ def generate_illustrations() -> Response | tuple[Response, int]: try: progress_manager.update(token, {"illustration_token": illust_token}) except KeyError: - pass + logger.warning( + "Could not link illustration to novel (progress entry %s not found).", + token, + ) thread = threading.Thread( target=_run_illustration_generation, diff --git a/tests/test_illustration_job.py b/tests/test_illustration_job.py index fcf0378..9fe7bba 100644 --- a/tests/test_illustration_job.py +++ b/tests/test_illustration_job.py @@ -139,6 +139,50 @@ def test_novel_token_records_illustration_token(self, client, mock_llm, monkeypa assert novel_state is not None assert novel_state.get("illustration_token") == illust_token + def test_warning_logged_when_novel_progress_entry_missing( + self, client, monkeypatch, caplog + ): + """A warning is emitted (not silently swallowed) when the novel progress + entry is deleted before illustration_token can be linked to it.""" + import logging + import novelforge.config as config + import novelforge.routes.export as export_module + from novelforge.progress import progress_manager as pm + + monkeypatch.setattr(config, "IMAGE_API_KEY", "key") + # Prevent the background thread from running so the test stays focused. + monkeypatch.setattr( + export_module.threading, + "Thread", + lambda *a, **kw: type("T", (), {"start": lambda s: None, "daemon": True})(), + ) + + # Patch progress_manager.update so that the first call (linking + # illustration_token onto the novel entry) raises KeyError, simulating + # a deleted entry. + original_update = pm.update + + def _raise_on_novel_token(tok, data): + if "illustration_token" in data: + raise KeyError(tok) + return original_update(tok, data) + + monkeypatch.setattr(pm, "update", _raise_on_novel_token) + + token = "deleted-novel-link" + _done_novel(token) + + with caplog.at_level(logging.WARNING, logger="novelforge.routes.export"): + client.post("/generate_illustrations", + data=json.dumps({"token": token}), + content_type="application/json") + + warning_msgs = [r.message for r in caplog.records if r.levelno == logging.WARNING] + assert any(token in msg for msg in warning_msgs), ( + "Expected a warning mentioning the missing progress token, got: " + + str(warning_msgs) + ) + # --------------------------------------------------------------------------- # Background worker: success flow