← back to Wallco Ai
stage-la-toile-nb: emit gallery from REAL inserted IDs, not predicted ones
93e7589aed3500cd73af468f50b255acb5e81c5f · 2026-06-03 08:48:49 -0700 · Steve Abrams
Fixes the off-by-N 404 bug (2026-06-03): gallery HTML built inline with predicted IDs
(57280-57309) before the insert assigned real ones (57313-57342), so links 404'd while
designs were live. Now captures {id,title} from each RETURNING id, writes the gallery
after insert/publish, labeled LIVE only when --publish flipped is_published.
Files touched
M scripts/stage-la-toile-nb.js
Diff
commit 93e7589aed3500cd73af468f50b255acb5e81c5f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jun 3 08:48:49 2026 -0700
stage-la-toile-nb: emit gallery from REAL inserted IDs, not predicted ones
Fixes the off-by-N 404 bug (2026-06-03): gallery HTML built inline with predicted IDs
(57280-57309) before the insert assigned real ones (57313-57342), so links 404'd while
designs were live. Now captures {id,title} from each RETURNING id, writes the gallery
after insert/publish, labeled LIVE only when --publish flipped is_published.
---
scripts/stage-la-toile-nb.js | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/scripts/stage-la-toile-nb.js b/scripts/stage-la-toile-nb.js
index 9e21291..3a8a4bd 100644
--- a/scripts/stage-la-toile-nb.js
+++ b/scripts/stage-la-toile-nb.js
@@ -44,6 +44,8 @@ print(json.dumps([{'hex':'#{:02x}{:02x}{:02x}'.format(*c),'pct':round(n/tot*100,
}
const ids = [];
+const meta = []; // {id,title} captured from the REAL inserted rows — the gallery is built
+ // from these, never from predicted IDs (the off-by-N 404 bug, 2026-06-03)
for (let i = 0; i < 30; i++) {
const src = `/tmp/nb-toile-${String(i + 1).padStart(2, '0')}.png`;
if (!fs.existsSync(src)) { console.log(`scene ${i + 1}: MISSING ${src} — skip`); continue; }
@@ -61,6 +63,7 @@ RETURNING id;`;
const id = parseInt(psql(sql), 10);
psql(`UPDATE all_designs SET image_url='/designs/img/by-id/${id}' WHERE id=${id};`);
ids.push(id);
+ meta.push({ id, title });
console.log(`scene ${i + 1} "${title}" -> #${id} (dom ${dom})`);
}
fs.writeFileSync('/tmp/nb-toile-staged-ids.json', JSON.stringify(ids));
@@ -75,3 +78,39 @@ COMMIT;`;
const n = psql(`SELECT count(*) FROM all_designs WHERE id IN (${ids.join(',')}) AND is_published=TRUE;`);
console.log(`PUBLISHED (DB): ${n}/${ids.length} now is_published=TRUE`);
}
+
+// Build the gallery from the REAL inserted IDs (meta), AFTER insert/publish. The old flow
+// wrote the gallery with predicted/sequential IDs before the insert assigned real ones, so
+// every link 404'd (the 2026-06-03 off-by-33 bug). Label LIVE only when actually published.
+function htmlEsc(s){ return String(s).replace(/[&<>"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'}[c])); }
+function writeGallery(rows, published) {
+ if (!rows.length) { console.log('GALLERY skipped — no rows'); return; }
+ const status = published ? 'LIVE on wallco.ai' : 'STAGED (unpublished) — run with --publish to go live';
+ const first = rows[0].id, last = rows[rows.length - 1].id;
+ const cards = rows.map(m => ` <a class="card" href="https://wallco.ai/design/${m.id}" target="_blank" rel="noopener">
+ <img loading="lazy" src="https://wallco.ai/designs/img/by-id/${m.id}" alt="${htmlEsc(m.title)}">
+ <div class="cap">#${m.id} · ${htmlEsc(m.title)}</div>
+ </a>`).join('\n');
+ const html = `<!doctype html><html lang="en"><head><meta charset="utf-8">
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<title>LA Toile de Jouy — ${status}</title>
+<style>
+ body{margin:0;background:#0e0e10;color:#eee;font:14px/1.45 system-ui,-apple-system,sans-serif}
+ h1{font-weight:500;padding:22px 24px 0;margin:0}
+ p.sub{padding:4px 24px 0;margin:0;color:#9aa2ad}
+ .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;padding:20px 24px}
+ .card{display:block;background:#17171b;border:1px solid #26262c;border-radius:10px;overflow:hidden;text-decoration:none;color:inherit;transition:border-color .12s}
+ .card:hover{border-color:#5b8def}
+ .card img{width:100%;aspect-ratio:1;object-fit:cover;object-position:center 12%;display:block;background:#222}
+ .cap{padding:8px 10px;font-size:12px;color:#cfcfd6}
+</style></head><body>
+ <h1>LA Toile de Jouy — ${status}</h1>
+ <p class="sub">${rows.length} designs · IDs ${first}–${last} · built ${new Date().toISOString().slice(0,16).replace('T',' ')} UTC</p>
+ <div class="grid">
+${cards}
+ </div>
+</body></html>`;
+ fs.writeFileSync('/tmp/nb-toile-gallery.html', html);
+ console.log(`GALLERY -> /tmp/nb-toile-gallery.html (${rows.length} cards, real IDs ${first}-${last}, ${status})`);
+}
+writeGallery(meta, PUBLISH && ids.length > 0);
← e131ed2 wallco: flip 137 reviewed misclassified mural_panel->seamles
·
back to Wallco Ai
·
yolo loop 2026-06-03: ledger + tick 1 (route sweep clean, /c 1f7667f →