[object Object]

← back to Wallco Ai

drunk-curator: Prev/Next queue nav (buttons + , . [ ] keys) to go back/forward without deciding

3e0f4725c46ec7632b6a358d01a81aa68fdcfc21 · 2026-05-27 15:42:18 -0700 · Steve Abrams

Files touched

Diff

commit 3e0f4725c46ec7632b6a358d01a81aa68fdcfc21
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed May 27 15:42:18 2026 -0700

    drunk-curator: Prev/Next queue nav (buttons + , . [ ] keys) to go back/forward without deciding
---
 data/auto-decide-ledger.jsonl   | 93 +++++++++++++++++++++++++++++++++++++++++
 public/admin/drunk-curator.html | 24 +++++++----
 2 files changed, 110 insertions(+), 7 deletions(-)

diff --git a/data/auto-decide-ledger.jsonl b/data/auto-decide-ledger.jsonl
index 070eba8..9fd9a18 100644
--- a/data/auto-decide-ledger.jsonl
+++ b/data/auto-decide-ledger.jsonl
@@ -2198,3 +2198,96 @@
 {"t":"2026-05-27T22:37:38.461Z","id":39675,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of orangutans in flower wreaths."}
 {"t":"2026-05-27T22:37:41.042Z","id":39676,"verdict":"hot_candidate","n":9,"see":"I see a repeating pattern of orangutans in frames."}
 {"t":"2026-05-27T22:37:43.623Z","id":39677,"verdict":"hot_candidate","n":16,"see":"A repeating pattern of monkeys holding flowers."}
+{"t":"2026-05-27T22:37:48.947Z","id":39678,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of gorilla motifs surrounded by flowers."}
+{"t":"2026-05-27T22:37:51.785Z","id":39685,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:37:54.143Z","id":39686,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of giraffe motifs."}
+{"t":"2026-05-27T22:37:56.894Z","id":39702,"verdict":"hot_candidate","n":12,"see":"I see a repeating pattern of monkeys and bottles."}
+{"t":"2026-05-27T22:37:59.877Z","id":39703,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of monkeys drinking from bottles."}
+{"t":"2026-05-27T22:38:02.475Z","id":39704,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of monkeys with a bottle."}
+{"t":"2026-05-27T22:38:05.689Z","id":39718,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:08.491Z","id":39719,"verdict":"hot_candidate","n":3,"see":"A wallpaper tile with a repeating orangutan and flower motif."}
+{"t":"2026-05-27T22:38:11.810Z","id":39722,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:14.872Z","id":39723,"verdict":"hot_candidate","n":3,"see":"A repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:18.119Z","id":39724,"verdict":"hot_candidate","n":3,"see":"A repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:22.458Z","id":39725,"verdict":"hot_candidate","n":3,"see":"A repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:25.393Z","id":39727,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:28.309Z","id":39728,"verdict":"hot_candidate","n":3,"see":"A repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:31.319Z","id":39729,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:34.386Z","id":39730,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:37.818Z","id":39731,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"Two orangutan motifs with floral elements on a blue background."}
+{"t":"2026-05-27T22:38:40.835Z","id":39732,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:44.049Z","id":39733,"verdict":"not","reason":"too-few-instances (n=2<3)","see":"A wallpaper tile with orangutan and flower motifs."}
+{"t":"2026-05-27T22:38:47.209Z","id":39734,"verdict":"hot_candidate","n":3,"see":"I see a repeating pattern of orangutans and flowers."}
+{"t":"2026-05-27T22:38:50.306Z","id":39735,"verdict":"hot_candidate","n":12,"see":"I see a repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:38:52.653Z","id":39736,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of orangutans in flower wreaths."}
+{"t":"2026-05-27T22:38:55.622Z","id":39737,"verdict":"hot_candidate","n":16,"see":"A repeating pattern of monkeys holding flowers."}
+{"t":"2026-05-27T22:38:58.523Z","id":39738,"verdict":"hot_candidate","n":13,"see":"A repeating pattern of orangutans in flower wreaths."}
+{"t":"2026-05-27T22:39:01.070Z","id":39739,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of monkeys with flowers."}
+{"t":"2026-05-27T22:39:03.664Z","id":39740,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:39:06.943Z","id":39741,"verdict":"hot_candidate","n":16,"see":"A repeating pattern of orangutans surrounded by flowers."}
+{"t":"2026-05-27T22:39:09.725Z","id":39742,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of orangutans in flower wreaths."}
+{"t":"2026-05-27T22:39:12.548Z","id":39743,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of orangutans surrounded by flowers."}
+{"t":"2026-05-27T22:39:15.422Z","id":39744,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:39:18.102Z","id":39745,"verdict":"hot_candidate","n":6,"see":"I see a repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:39:21.120Z","id":39746,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:39:23.751Z","id":39747,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of monkeys in flower wreaths."}
+{"t":"2026-05-27T22:39:26.220Z","id":39748,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of orangutans with flowers."}
+{"t":"2026-05-27T22:39:28.791Z","id":39749,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of orangutans in flower wreaths."}
+{"t":"2026-05-27T22:39:31.211Z","id":39758,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of sloths in trees."}
+{"t":"2026-05-27T22:39:34.216Z","id":39759,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of sloths on branches."}
+{"t":"2026-05-27T22:39:37.306Z","id":39760,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of sloths hanging from branches."}
+{"t":"2026-05-27T22:39:39.873Z","id":39836,"verdict":"hot_candidate","n":15,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:39:42.957Z","id":39847,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of monkeys holding vases."}
+{"t":"2026-05-27T22:39:45.793Z","id":39848,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of monkeys and vases."}
+{"t":"2026-05-27T22:39:48.452Z","id":39853,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of gorillas in cages with champagne."}
+{"t":"2026-05-27T22:39:51.386Z","id":39854,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of a bottle and glasses between two columns."}
+{"t":"2026-05-27T22:39:54.333Z","id":39920,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of lemurs and tropical leaves."}
+{"t":"2026-05-27T22:39:57.481Z","id":39921,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of monkey and monstera motifs."}
+{"t":"2026-05-27T22:40:00.002Z","id":39922,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of lemurs with babies."}
+{"t":"2026-05-27T22:40:03.138Z","id":39936,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of raccoons."}
+{"t":"2026-05-27T22:40:06.269Z","id":39937,"verdict":"hot_candidate","n":20,"see":"A repeating pattern of cats and raccoons."}
+{"t":"2026-05-27T22:40:08.856Z","id":39947,"verdict":"hot_candidate","n":8,"see":"A repeating pattern of giraffe pairs."}
+{"t":"2026-05-27T22:40:11.605Z","id":39948,"verdict":"hot_candidate","n":21,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:40:14.486Z","id":39949,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:40:17.364Z","id":39958,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of parrots on branches."}
+{"t":"2026-05-27T22:40:20.531Z","id":39981,"verdict":"hot_candidate","n":14,"see":"A repeating pattern of raccoons and foxes."}
+{"t":"2026-05-27T22:40:23.578Z","id":40000,"verdict":"hot_candidate","n":16,"see":"A repeating pattern of trees and deer."}
+{"t":"2026-05-27T22:40:26.588Z","id":40001,"verdict":"hot_candidate","n":9,"see":"I see a repeating pattern of trees and deer."}
+{"t":"2026-05-27T22:40:29.389Z","id":40010,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of deer and trees."}
+{"t":"2026-05-27T22:40:32.130Z","id":40011,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of deer and trees."}
+{"t":"2026-05-27T22:40:34.935Z","id":40026,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:40:37.672Z","id":40027,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of giraffes and trees."}
+{"t":"2026-05-27T22:40:40.250Z","id":40031,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of sloths with wine glasses."}
+{"t":"2026-05-27T22:40:43.013Z","id":40209,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of sloths hanging from branches."}
+{"t":"2026-05-27T22:40:45.519Z","id":40241,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of cockatoos on branches."}
+{"t":"2026-05-27T22:40:48.031Z","id":40242,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of parrots on branches."}
+{"t":"2026-05-27T22:40:50.968Z","id":40268,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of monkey and plant motifs."}
+{"t":"2026-05-27T22:40:54.072Z","id":40269,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of tropical plants and monkeys."}
+{"t":"2026-05-27T22:40:56.989Z","id":40270,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of trees and monkeys."}
+{"t":"2026-05-27T22:40:59.515Z","id":40271,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of parrots on palm fronds."}
+{"t":"2026-05-27T22:41:02.095Z","id":40272,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of palm trees with parrots."}
+{"t":"2026-05-27T22:41:04.964Z","id":40273,"verdict":"hot_candidate","n":9,"see":"I see a repeating pattern of pairs of birds on branches."}
+{"t":"2026-05-27T22:41:07.963Z","id":40300,"verdict":"hot_candidate","n":15,"see":"A repeating pattern of white floral and bird motifs on a green background."}
+{"t":"2026-05-27T22:41:10.954Z","id":40301,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of white parrots on branches with tropical leaves."}
+{"t":"2026-05-27T22:41:13.798Z","id":40302,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of white parrots on branches with leaves on a dark purple background."}
+{"t":"2026-05-27T22:41:16.848Z","id":40323,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of cockatoos on branches."}
+{"t":"2026-05-27T22:41:19.790Z","id":40324,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of parrots and tropical foliage."}
+{"t":"2026-05-27T22:41:22.618Z","id":40341,"verdict":"hot_candidate","n":8,"see":"A repeating pattern of giraffes and bamboo."}
+{"t":"2026-05-27T22:41:25.651Z","id":40342,"verdict":"hot_candidate","n":6,"see":"A repeating wallpaper pattern of giraffes and architectural elements."}
+{"t":"2026-05-27T22:41:28.126Z","id":40355,"verdict":"hot_candidate","n":12,"see":"A repeating pattern of monkeys and vases."}
+{"t":"2026-05-27T22:41:31.172Z","id":40356,"verdict":"hot_candidate","n":15,"see":"A repeating pattern of monkeys on pillars."}
+{"t":"2026-05-27T22:41:34.307Z","id":40422,"verdict":"hot_candidate","n":10,"see":"A repeating pattern of elephants and trees."}
+{"t":"2026-05-27T22:41:37.151Z","id":40423,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of elephants and trees on a brick background."}
+{"t":"2026-05-27T22:41:40.168Z","id":40443,"verdict":"hot_candidate","n":10,"see":"A repeating pattern of pandas and raccoons."}
+{"t":"2026-05-27T22:41:43.040Z","id":40444,"verdict":"hot_candidate","n":8,"see":"A repeating pattern of pandas and winged raccoons."}
+{"t":"2026-05-27T22:41:45.804Z","id":40446,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of cats in boxes."}
+{"t":"2026-05-27T22:41:48.501Z","id":40447,"verdict":"hot_candidate","n":7,"see":"I see a repeating pattern of cats in frames."}
+{"t":"2026-05-27T22:41:51.530Z","id":40448,"verdict":"hot_candidate","n":81,"see":"A repeating field of cartoon bears."}
+{"t":"2026-05-27T22:41:54.516Z","id":40449,"verdict":"hot_candidate","n":9,"see":"I see a repeating pattern of green elephants."}
+{"t":"2026-05-27T22:41:57.535Z","id":40509,"verdict":"hot_candidate","n":14,"see":"A repeating pattern of giraffes and palm trees."}
+{"t":"2026-05-27T22:42:00.121Z","id":40510,"verdict":"hot_candidate","n":9,"see":"A repeating pattern of giraffes and palm trees."}
+{"t":"2026-05-27T22:42:03.402Z","id":40511,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of giraffes and palm trees."}
+{"t":"2026-05-27T22:42:06.372Z","id":40522,"verdict":"hot_candidate","n":15,"see":"A repeating wallpaper pattern with bird motifs."}
+{"t":"2026-05-27T22:42:09.158Z","id":40523,"verdict":"hot_candidate","n":7,"see":"A repeating pattern of birds in trees."}
+{"t":"2026-05-27T22:42:11.900Z","id":40524,"verdict":"hot_candidate","n":6,"see":"I see a repeating pattern of parrots on branches."}
+{"t":"2026-05-27T22:42:15.043Z","id":40538,"verdict":"hot_candidate","n":6,"see":"A repeating pattern of giraffes and palm trees."}
diff --git a/public/admin/drunk-curator.html b/public/admin/drunk-curator.html
index f4d2f7e..be7747c 100644
--- a/public/admin/drunk-curator.html
+++ b/public/admin/drunk-curator.html
@@ -42,6 +42,10 @@
   .fix{background:#c98a00;color:#1a1a1a;} .extract{background:#2e7d32;color:#fff;}
   .btns button{padding:13px 24px;}
   .hint{font-size:11px;color:var(--mut);}
+  .nav{display:flex;align-items:center;gap:14px;}
+  .nav .navb{background:#2a2a2a;color:var(--ink);border:1px solid #444;padding:8px 16px;font-size:13px;font-weight:600;border-radius:10px;}
+  .nav .navb:disabled{opacity:.3;cursor:default;}
+  .nav .pos{font-size:12px;color:var(--mut);font-variant-numeric:tabular-nums;min-width:96px;text-align:center;}
   .done{text-align:center;color:var(--mut);margin-top:18vh;} .done h2{color:var(--ink);}
   .flash{position:fixed;inset:0;pointer-events:none;opacity:0;transition:opacity .25s;font-size:140px;display:flex;align-items:center;justify-content:center;z-index:9;}
   .flash.show{opacity:1;}
@@ -81,7 +85,10 @@ const $=s=>document.querySelector(s);
 const ADMIN=new URLSearchParams(location.search).get('admin');
 const CATEGORY=new URLSearchParams(location.search).get('category')||'';
 const q=s=>ADMIN?(s+(s.includes('?')?'&':'?')+'admin='+encodeURIComponent(ADMIN)):s;
-let QUEUE=[], i=0, hot=0, not=0, streak=0;
+let QUEUE=[], i=0, hot=0, not=0, streak=0, decided={};
+// Move through the queue WITHOUT deciding — lets Steve go back/forward to review
+// or fix items. Clamps to [0, length] (length = the cleared screen).
+function go(delta){ if(busy) return; const ni=i+delta; if(ni<0||ni>QUEUE.length) return; i=ni; render(); }
 let autoIdOn = localStorage.getItem('drunk_autoid')==='1';   // Auto-ID is OPT-IN (off by default — saves Gemini cost)
 function fmtDate(iso){ if(!iso)return''; try{return new Date(iso).toLocaleString(undefined,{month:'short',day:'numeric',hour:'numeric',minute:'2-digit'});}catch{return iso;} }
 function flash(e){ const f=$('#flash'); f.textContent=e; f.classList.add('show'); setTimeout(()=>f.classList.remove('show'),250); }
@@ -89,7 +96,7 @@ function render(){
   $('#seen').textContent=hot+not; $('#hot').textContent=hot; $('#not').textContent=not;
   $('#left').textContent=Math.max(0,QUEUE.length-i);
   $('#streak').textContent= streak>=3?`🔥×${streak} streak`:'';
-  if(i>=QUEUE.length){ $('#stage').innerHTML=`<div class="done"><h2>Pile cleared 🎉</h2><div>${hot} published · ${not} → defect registry</div><div class="hint" style="margin-top:10px">Generate more, then refresh.</div></div>`; return; }
+  if(i>=QUEUE.length){ $('#stage').innerHTML=`<div class="done"><h2>Pile cleared 🎉</h2><div>${hot} published · ${not} → defect registry</div><div class="hint" style="margin-top:10px">Generate more, then refresh.</div><div class="nav" style="justify-content:center;margin-top:16px"><button class="navb" onclick="go(-1)">‹ Back to last item</button></div></div>`; return; }
   const d=QUEUE[i], src=`/designs/img/by-id/${d.id}`;
   $('#stage').innerHTML=`
     <div class="panes">
@@ -104,8 +111,9 @@ function render(){
     </div>
     <div class="meta"><span>#${d.id} · ${d.category||''}</span><span>🕓 ${fmtDate(d.created_at)}</span></div>
     <div class="prompt" onclick="this.classList.toggle('open')">${(d.prompt||'').replace(/</g,'&lt;').slice(0,240)}</div>
+    <div class="nav"><button class="navb" onclick="go(-1)" ${i<=0?'disabled':''}>‹ Prev</button><span class="pos">${i+1} / ${QUEUE.length}${decided[d.id]?' · '+decided[d.id]:''}</span><button class="navb" onclick="go(1)" ${i>=QUEUE.length-1?'disabled':''}>Next ›</button></div>
     <div class="btns"><button class="hot" onclick="decide('hot')">🔥 HOT</button><button class="fix" onclick="decide('fix')">🔧 Fix</button><button class="not" onclick="decide('not')">🗑 Trash</button><button class="extract" onclick="extract()">✂️ Extract</button></div>
-    <div class="hint">🔥/→ hot · 🔧/F fix · 🗑/← trash · ✂️/E extract opaque motif → elements · dotted = auto-detected errors</div>`;
+    <div class="hint">🔥/→ hot · 🔧/F fix · 🗑/← trash · ✂️/E extract · ‹ Prev , / [ · Next › . / ] (skip without deciding) · dotted = auto-detected errors</div>`;
   if(autoIdOn) autoIdCurrent();   // opt-in: only scan when the Auto-ID toggle is on
 }
 
@@ -162,14 +170,14 @@ async function decide(v){
   // it, not lost). Tell Steve why it didn't go live + offer a one-click force-publish,
   // then advance — no more loop on the same item.
   if(v==='hot' && j.gate_held){
-    hot++; flash('🔧');
+    hot++; flash('🔧'); decided[d.id]='held';
     const reasons=(j.reasons||[]).join(' · ')||'failed publish gate';
     $('#stage').insertAdjacentHTML('afterbegin',`<div id="saveerr" style="position:fixed;top:62px;left:50%;transform:translateX(-50%);background:#8a6d1f;color:#fff;padding:8px 16px;border-radius:8px;z-index:99;font-size:13px;max-width:90vw">🔧 #${d.id} loved & held — not auto-published: ${reasons}. <a href="#" id="forcepub" data-id="${d.id}" style="color:#ffe9a8;font-weight:600;text-decoration:underline">Publish anyway</a></div>`);
     setTimeout(()=>document.getElementById('saveerr')?.remove(),8000);
     document.getElementById('forcepub')?.addEventListener('click',ev=>{ev.preventDefault();forcePublish(parseInt(ev.target.dataset.id,10));});
-  } else if(v==='hot'){hot++;streak++;flash('🔥');}
-  else if(v==='fix'){flash('🔧');}
-  else {not++;streak=0;flash('👎');}
+  } else if(v==='hot'){hot++;streak++;flash('🔥');decided[d.id]='hot';}
+  else if(v==='fix'){flash('🔧');decided[d.id]='fix';}
+  else {not++;streak=0;flash('👎');decided[d.id]='trash';}
   i++; busy=false; render();
 }
 // One-click override: re-POST the HOT with force=true to bypass the gate (Steve's
@@ -184,6 +192,8 @@ async function forcePublish(id){
 }
 document.addEventListener('keydown',e=>{ const k=e.key.toLowerCase();
   if(e.target.tagName==='SELECT')return;
+  if(k===','||e.key==='[')return go(-1);          // prev — skip back without deciding
+  if(k==='.'||e.key===']')return go(1);           // next — skip forward without deciding
   if(e.key==='ArrowRight'||k==='h')decide('hot'); else if(e.key==='ArrowLeft'||k==='n')decide('not');
   else if(k==='f')decide('fix'); else if(k==='e')extract(); });
 

← 6fd11d4 curator HOT: gate-failed pick saves+holds (no lost vote/loop  ·  back to Wallco Ai  ·  drunk-curator: held-HOT toast attaches to body so render() c 6c3d280 →