[object Object]

← back to Wallco Ai

Fix AI-recolor publish gate: child SKUs land is_published=FALSE + carry parent_design_id (was auto-publishing orphans)

5b6ed8d842e46aa2d7bbfd4a1d170ccf364ec509 · 2026-06-12 07:41:54 -0700 · Steve Abrams

Files touched

Diff

commit 5b6ed8d842e46aa2d7bbfd4a1d170ccf364ec509
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Jun 12 07:41:54 2026 -0700

    Fix AI-recolor publish gate: child SKUs land is_published=FALSE + carry parent_design_id (was auto-publishing orphans)
---
 server.js | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/server.js b/server.js
index f5ebfe4..7431856 100644
--- a/server.js
+++ b/server.js
@@ -25422,14 +25422,26 @@ app.post('/api/design/:id/recolor', sgRecolorGate, express.json(), async (req, r
       ? 'ARRAY[' + d.motifs.map(t => "'" + String(t).replace(/'/g, "''") + "'").join(',') + ']::text[]'
       : "ARRAY[]::text[]";
     const promptDesc = (newTitle + ' — ' + prompt).slice(0, 1800).replace(/'/g, "''");
+    // is_published=FALSE: every recolor is a CHILD SKU of an already-passed
+    // root, same prompt class. It lands unpublished — only an explicit admin
+    // click publishes it (mirrors promoteToSpoonRow + the /bake sibling). The
+    // old TRUE here was a gate bug (children must never auto-publish). Also
+    // carry parent_design_id so the child has lineage back to its root, and
+    // only set it when the source design actually exists in PG (prod PG is
+    // sparse — an id that isn't a real spoon row would orphan the FK-less ref).
+    let parentInPg = false;
+    try {
+      const chk = psqlQuery(`SELECT 1 FROM spoon_all_designs WHERE id=${id} LIMIT 1;`);
+      parentInPg = !!(chk && chk.trim());
+    } catch (e) { /* table/col may differ on this box → leave NULL */ }
     const insertSql = `INSERT INTO spoon_all_designs
       (kind, width_in, height_in, generator, prompt, seed, dominant_hex,
-       local_path, image_url, category, motifs, tags, is_published, request_text)
+       local_path, image_url, category, motifs, tags, is_published, parent_design_id, request_text)
       VALUES ('seamless_tile', 24, 24, 'gemini-2.5-flash-image-edit',
         '${promptDesc}', ${seed}, ${domHex ? "'" + domHex + "'" : 'NULL'},
         '${outPath.replace(/'/g, "''")}', '/designs/img/${filename}',
         ${"'" + (d.category || 'recolor') + "'"},
-        ${motifsSql}, ${tagSql}, TRUE,
+        ${motifsSql}, ${tagSql}, FALSE, ${parentInPg ? id : 'NULL'},
         '${("Tone-on-tone " + targetLabel + " recolor of design " + id).replace(/'/g, "''")}')
       RETURNING id;`;
     const newIdStr = psqlQuery(insertSql);
@@ -25448,7 +25460,8 @@ app.post('/api/design/:id/recolor', sgRecolorGate, express.json(), async (req, r
       local_path: outPath,
       generator: 'gemini-2.5-flash-image-edit',
       seed,
-      is_published: true,
+      is_published: false,
+      parent_design_id: parentInPg ? id : null,
       created_at: new Date().toISOString(),
       motifs: d.motifs || [],
       tags: baseTags,

← a0a8321 Throttle overnight seam loop: max-retries default 8→4 (load  ·  back to Wallco Ai  ·  overnight-seam-loop: route DTD vote tally to stderr so it la f7ada02 →