From 9974b93379660c4b1f5415ab0f5a0d23715de178 Mon Sep 17 00:00:00 2001 From: type-two Date: Wed, 8 Jul 2026 20:13:50 +1000 Subject: [PATCH] feat(requeue): --force, for when Flow succeeds at the wrong picture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cal79_throbbing was recorded 'success' with 4 assets — but they were Kenner Alien toy ads, not the Throbbing Gristle clifftop it asked for. Flow refused the Kenner brief, drew a Voyager plate instead, and emitted the toy variants late, so the harvester (which attributes whatever NEW tiles appear to the CURRENT task) filed them under the next task in the queue. Successes stay protected by default — re-running one spends credits for an asset you already have. --force is the deliberate override, and it says so before it acts. --force with no ids matches nothing. Known limitation, not fixed here: asset->task attribution is a grid diff, so a late or refused generation can land under its successor. Check the pictures, not just the status. Co-Authored-By: Claude Opus 4.8 --- requeue.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/requeue.py b/requeue.py index 99d2d17..f0a7c4e 100644 --- a/requeue.py +++ b/requeue.py @@ -10,6 +10,10 @@ and we don't re-bill by accident. This is the deliberate, explicit way to retry. python3 requeue.py cal79_ # do it (writes a .bak first) python3 requeue.py --failed # every failed task python3 requeue.py cal79_disco cal79_tmi # exact ids + python3 requeue.py --force cal79_throbbing # re-run a SUCCESS (it drew the wrong thing) + +Successes are protected: re-running one spends credits for an asset you already have. +--force is the deliberate override, for when Flow succeeded at the wrong picture. Stop the queue server first, or it may rewrite the file under you. """ @@ -34,6 +38,7 @@ def main(): print(__doc__) return 1 dry = '--dry' in args + force = '--force' in args only_failed = '--failed' in args pats = [a for a in args if not a.startswith('--')] rs = rows() @@ -45,16 +50,18 @@ def main(): return 0 def hit(r): - if r['status'] == 'success': + if r['status'] == 'success' and not force: return False # never re-run a success; that's just burning credits - if only_failed and r['status'] == 'failed': - return True + if only_failed: + return r['status'] == 'failed' return any(r['id'] == p or r['id'].startswith(p) for p in pats) doomed = [r for r in rs if hit(r)] if not doomed: - print('nothing matched (successes are never requeued)') + print('nothing matched (successes are never requeued — pass --force if Flow drew the wrong thing)') return 1 + if force and any(r['status'] == 'success' for r in doomed): + print('--force: re-running SUCCESSES. This spends credits for assets you already have.') for r in doomed: print(f" requeue {r['id']:<24} {r['status']:<10} {str(r.get('error',''))[:46]}") print(f"\n{len(doomed)} task(s){' [DRY RUN]' if dry else ''}")