feat(requeue): --force, for when Flow succeeds at the wrong picture
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 <noreply@anthropic.com>
This commit is contained in:
parent
84fa103125
commit
9974b93379
15
requeue.py
15
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 cal79_ # do it (writes a .bak first)
|
||||||
python3 requeue.py --failed # every failed task
|
python3 requeue.py --failed # every failed task
|
||||||
python3 requeue.py cal79_disco cal79_tmi # exact ids
|
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.
|
Stop the queue server first, or it may rewrite the file under you.
|
||||||
"""
|
"""
|
||||||
@ -34,6 +38,7 @@ def main():
|
|||||||
print(__doc__)
|
print(__doc__)
|
||||||
return 1
|
return 1
|
||||||
dry = '--dry' in args
|
dry = '--dry' in args
|
||||||
|
force = '--force' in args
|
||||||
only_failed = '--failed' in args
|
only_failed = '--failed' in args
|
||||||
pats = [a for a in args if not a.startswith('--')]
|
pats = [a for a in args if not a.startswith('--')]
|
||||||
rs = rows()
|
rs = rows()
|
||||||
@ -45,16 +50,18 @@ def main():
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def hit(r):
|
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
|
return False # never re-run a success; that's just burning credits
|
||||||
if only_failed and r['status'] == 'failed':
|
if only_failed:
|
||||||
return True
|
return r['status'] == 'failed'
|
||||||
return any(r['id'] == p or r['id'].startswith(p) for p in pats)
|
return any(r['id'] == p or r['id'].startswith(p) for p in pats)
|
||||||
|
|
||||||
doomed = [r for r in rs if hit(r)]
|
doomed = [r for r in rs if hit(r)]
|
||||||
if not doomed:
|
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
|
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:
|
for r in doomed:
|
||||||
print(f" requeue {r['id']:<24} {r['status']:<10} {str(r.get('error',''))[:46]}")
|
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 ''}")
|
print(f"\n{len(doomed)} task(s){' [DRY RUN]' if dry else ''}")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user