diff --git a/cauldron/db.py b/cauldron/db.py index f95e70f..71c85f5 100644 --- a/cauldron/db.py +++ b/cauldron/db.py @@ -972,13 +972,14 @@ class DB: ) def finalize_sterilize_job(self, job_id: int, *, state: str) -> None: - """Move job to a terminal state (review/done/failed/cancelled). + """Move job to a new state. Will NOT overwrite a terminal state + (done / failed / cancelled) — that's the anti-zombie guard that + keeps user cancels from being silently replaced when the daemon + thread limps to the finish line. - Will NOT overwrite a job that's already terminal — if a runner is - about to call finalize('done') but the row was set to 'cancelled' - externally, we leave the cancellation in place. This is the - anti-zombie guard that keeps user cancels from being silently - replaced when the daemon thread limps to the finish line.""" + Allowed source states: running, applying, review. The review state + is part of the normal flow (walk done → review → user approves + → applying), so transitions out of review must work.""" with self.conn() as c, c.cursor() as cur: cur.execute( """ @@ -989,7 +990,7 @@ class DB: last_progress_at = NOW(), current_slug = NULL WHERE id=%s - AND state IN ('running','applying') + AND state NOT IN ('done','failed','cancelled') """, (state, state, job_id), ) @@ -1169,6 +1170,9 @@ class DB: ) def finalize_consolidate_job(self, job_id: int, *, state: str) -> None: + """Same anti-zombie guard as finalize_sterilize_job — won't overwrite + a terminal state (done/failed/cancelled), but allows the normal + running→review→applying→done flow.""" with self.conn() as c, c.cursor() as cur: cur.execute( """UPDATE cauldron_consolidate_jobs @@ -1178,7 +1182,7 @@ class DB: last_progress_at = NOW(), current_cluster = NULL WHERE id=%s - AND state IN ('running','applying')""", + AND state NOT IN ('done','failed','cancelled')""", (state, state, job_id), )