← back to Wallco Ai
Fix overnight seam loop: (1) generator exits 0 on completed wave not 1-on-any-fail (was freezing manifest index → infinite re-run + orphan dupes); (2) idempotency guard skips roots with existing PASS candidate; (3) point loop at generalized reroll.py not scope-locked reroll-2.py; (4) retire unrescuable 43199 macaw + 54385 peacock
dd74023d1a1ce0166f6e20436d929bb4c0330178 · 2026-06-11 20:04:15 -0700 · Steve Abrams
Files touched
M data/seam-wave-exclude.txtM scripts/controlnet-anchored-reroll.pyM scripts/overnight-seam-loop.sh
Diff
commit dd74023d1a1ce0166f6e20436d929bb4c0330178
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jun 11 20:04:15 2026 -0700
Fix overnight seam loop: (1) generator exits 0 on completed wave not 1-on-any-fail (was freezing manifest index → infinite re-run + orphan dupes); (2) idempotency guard skips roots with existing PASS candidate; (3) point loop at generalized reroll.py not scope-locked reroll-2.py; (4) retire unrescuable 43199 macaw + 54385 peacock
---
data/seam-wave-exclude.txt | 2 ++
scripts/controlnet-anchored-reroll.py | 30 +++++++++++++++++++++++++++++-
scripts/overnight-seam-loop.sh | 8 +++++---
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/data/seam-wave-exclude.txt b/data/seam-wave-exclude.txt
index 08fd18c..8dca1bf 100644
--- a/data/seam-wave-exclude.txt
+++ b/data/seam-wave-exclude.txt
@@ -10,3 +10,5 @@
54076 # orangutan — wine-glass-dominant; best roll PASS-seamless but no animal
54266 # tree frog — champagne-coupe-dominant; best roll PASS-seamless but no animal
+43199 # macaw — Wave 1: 8 retries, motif edge never reached strict <=6; unrescuable
+54385 # peacock — Wave 1: fanned feathers cross the tile boundary; 8 retries, no clear
diff --git a/scripts/controlnet-anchored-reroll.py b/scripts/controlnet-anchored-reroll.py
index 3dcc71b..94a52a8 100644
--- a/scripts/controlnet-anchored-reroll.py
+++ b/scripts/controlnet-anchored-reroll.py
@@ -91,8 +91,29 @@ def main():
print(json.dumps({'error': 'no ids'}), file=sys.stderr)
sys.exit(2)
+ # Idempotency: roots that already have a PASS candidate in the queue are DONE.
+ # Re-processing them would INSERT a duplicate (all_designs is INSERT-only — dupes
+ # can't be cleaned up). Skip them. This makes the wave runner safe to re-invoke.
+ done_roots = set()
+ try:
+ with open(QUEUE) as _q:
+ for _line in _q:
+ try:
+ _row = json.loads(_line)
+ if _row.get('ok') and _row.get('edge_verdict') == 'PASS':
+ done_roots.add(int(_row.get('root_id')))
+ except Exception:
+ pass
+ except FileNotFoundError:
+ pass
+
results = []
for i, rid in enumerate(ids):
+ if rid in done_roots:
+ results.append({'root_id': rid, 'ok': True, 'skipped': 'already has PASS candidate',
+ 'edge_verdict': 'PASS', 'generator': 'controlnet-anchored-reroll'})
+ print(f"=> root {rid}: SKIP (already has PASS candidate)", file=sys.stderr)
+ continue
ground = args.ground or cnar.GROUNDS[i % len(cnar.GROUNDS)]
cfg = cfg_for(rid, ground)
try:
@@ -116,7 +137,14 @@ def main():
f"ground={r.get('ground')}", file=sys.stderr)
print(json.dumps(results, indent=2))
- sys.exit(0 if all(r.get('ok') for r in results) else 1)
+ # Exit 0 when the wave RAN — a root that "couldn't clear" after retries is a
+ # normal terminal outcome (it won't clear on a re-run), so the wave runner MUST
+ # advance its manifest index past it. Exit non-zero ONLY if every root threw an
+ # execution exception (e.g. ComfyUI down) — that's a real infra failure where the
+ # runner should NOT advance (it retries; the loop's zero-PASS-streak stop catches
+ # a sustained outage). Per-root non-clears never block manifest progress.
+ all_errored = bool(results) and all('error' in r for r in results)
+ sys.exit(1 if all_errored else 0)
if __name__ == '__main__':
diff --git a/scripts/overnight-seam-loop.sh b/scripts/overnight-seam-loop.sh
index 0b31613..32f627a 100755
--- a/scripts/overnight-seam-loop.sh
+++ b/scripts/overnight-seam-loop.sh
@@ -52,9 +52,11 @@ MANIFEST="data/seam-wave-roots.txt"
DTD_PANEL="$HOME/.claude/skills/dtd/scripts/panel.sh"
CNCP="http://127.0.0.1:3333/api/wins"
-# Generator: the generalized retry-generator (confirmed by the Wave-1 agent).
-# Override at launch with SEAM_GENERATOR=... ; default is the reroll-2 retry generator.
-SEAM_GENERATOR="${SEAM_GENERATOR:-scripts/controlnet-anchored-reroll-2.py}"
+# Generator: the GENERALIZED retry-generator (arbitrary --ids). reroll-2.py is hard
+# scope-locked to {54076,54266} and refuses every other id — using it empties every
+# wave. reroll.py accepts any animal-forward root and has the idempotency guard.
+# Override at launch with SEAM_GENERATOR=...
+SEAM_GENERATOR="${SEAM_GENERATOR:-scripts/controlnet-anchored-reroll.py}"
WAVE_SIZE="${WAVE_SIZE:-20}"
DRY_RUN="${DRY_RUN:-0}"
← 4992ea4 seam-wave Wave 1: 1/3 roots cleared (55272 elephant -> 10000
·
back to Wallco Ai
·
Fix overnight loop DTD gate: capture only dtd_decide's final f591bcd →