[object Object]

← back to Wallco Ai

Harden pattern-generation engine per Claude-Codex debate: gate --texture-cat to material enum (no raw SQL interpolation), hex_to_hls survives 3-digit/malformed hex (was a snapshot-abort), prefix-match animal categories so drunk-animals-* variants get motif naming, re.escape animal regex, drop dead goose entry

50ab4a2cd90f000c2b744d3368087a6f851d58d3 · 2026-05-31 19:20:30 -0700 · Steve

Files touched

Diff

commit 50ab4a2cd90f000c2b744d3368087a6f851d58d3
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun May 31 19:20:30 2026 -0700

    Harden pattern-generation engine per Claude-Codex debate: gate --texture-cat to material enum (no raw SQL interpolation), hex_to_hls survives 3-digit/malformed hex (was a snapshot-abort), prefix-match animal categories so drunk-animals-* variants get motif naming, re.escape animal regex, drop dead goose entry
---
 scripts/gen-luxe.js                 | 14 +++++++++++++-
 scripts/refresh_designs_snapshot.py | 22 ++++++++++++++++------
 2 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/scripts/gen-luxe.js b/scripts/gen-luxe.js
index 62b315b..058d513 100644
--- a/scripts/gen-luxe.js
+++ b/scripts/gen-luxe.js
@@ -124,8 +124,20 @@ const SKU_PREFIX = {
   sisal: 'sis', jute: 'jut', seagrass: 'sea', abaca: 'aba',
 };
 const ALL_PREFIX = 'grs|grass|lin|sil|crk|cork|raf|mad|mic|nat|sis|jut|sea|aba';
+// Allowed material categories — gate --texture-cat to this set so an arbitrary
+// CLI value can never be interpolated raw into the SQL regex (codex review,
+// 2026-06-01). Unknown/compound cats fall through to the default natural pool.
+const MATERIAL_CATS = new Set([
+  'grasscloth', 'linen', 'silk', 'cork', 'raffia', 'mica', 'madagascar',
+  'sisal', 'abaca', 'seagrass', 'jute', 'hemp', 'arrowroot', 'paperweave',
+  'bamboo', 'reed', 'natural',
+]);
 function pickTextureBrief(category) {
-  const cat = (category || '').toLowerCase();
+  let cat = (category || '').toLowerCase().trim();
+  if (cat && !MATERIAL_CATS.has(cat)) {
+    console.warn(`[gen-luxe] unknown --texture-cat="${cat}" — using default natural-texture pool`);
+    cat = '';
+  }
   const pfx = SKU_PREFIX[cat] || '';
   const where = cat
     ? `AND (p.title ~* '\\m(${cat})\\M'${pfx ? ` OR p.sku ~* '^(${pfx})[-_]'` : ''})`
diff --git a/scripts/refresh_designs_snapshot.py b/scripts/refresh_designs_snapshot.py
index 11c096b..2febb01 100644
--- a/scripts/refresh_designs_snapshot.py
+++ b/scripts/refresh_designs_snapshot.py
@@ -32,6 +32,12 @@ def psql_json(sql):
 def hex_to_hls(hex_):
     if not hex_ or not hex_.startswith('#'): return (0,0.5,0)
     h = hex_.lstrip('#')
+    if len(h) == 3:  # CSS shorthand #abc → #aabbcc
+        h = ''.join(c*2 for c in h)
+    # Guard malformed hex (short/long/non-hex) — a bad dominant_hex must NOT
+    # abort the whole snapshot rebuild (codex review, 2026-06-01).
+    if len(h) < 6 or any(c not in '0123456789abcdefABCDEF' for c in h[:6]):
+        return (0, 0.5, 0)
     r = int(h[0:2],16)/255; g = int(h[2:4],16)/255; b = int(h[4:6],16)/255
     return colorsys.rgb_to_hls(r,g,b)
 
@@ -102,8 +108,7 @@ ANIMALS = ['peacock','giraffe','elephant','orangutan','capybara','bullfrog',
            'chameleon','turtle','toad','hummingbird','monkey','frog']
 # display plural override; default is Capitalize + 's'
 ANIMAL_PLURAL = {'fox':'Foxes','hare':'Hares','stag':'Stags','deer':'Deer',
-                 'goose':'Geese','monkey':'Monkeys',
-                 'bullfrog':'Frogs','treefrog':'Frogs'}
+                 'monkey':'Monkeys','bullfrog':'Frogs','treefrog':'Frogs'}
 def animal_in(prompt):
     # The luxe-regen prompt is structured "...Ground: <SKU may name an animal>.
     # Motif: <hero animal> ...". Search the Motif clause ONLY so a ground SKU like
@@ -114,7 +119,7 @@ def animal_in(prompt):
     hay = m.group(1) if m else p
     best = None; best_pos = len(hay) + 1
     for a in ANIMALS:
-        mm = re.search(r'\b' + a + r'(?:s|es)?\b', hay)
+        mm = re.search(r'\b' + re.escape(a) + r'(?:s|es)?\b', hay)
         if mm and mm.start() < best_pos:
             best, best_pos = a, mm.start()
     if best:
@@ -158,10 +163,15 @@ def ground_hex(prompt):
 
 def title_for(cat, hex_, id_, prompt=None):
     color = colorway_name(ground_hex(prompt) or hex_)
-    # Animal categories: name from the actual creature → "Peacock Carouse in Verdigris"
-    if cat in ANIMAL_NOUNS:
+    # Animal categories: name from the actual creature → "Peacock Carouse in Verdigris".
+    # PREFIX match (not exact) so variants like drunk-animals-designer / -sample5 /
+    # stoned-animals-* still get motif-aware naming (codex+claude review, 2026-06-01 —
+    # the file's own "exact-match vs prefix allowlist gap" trap).
+    akey = next((k for k in ANIMAL_NOUNS if cat == k or (cat or '').startswith(k)), None)
+    if akey:
         animal = animal_in(prompt)
-        noun = ANIMAL_NOUNS[cat][id_ % len(ANIMAL_NOUNS[cat])]
+        pool = ANIMAL_NOUNS[akey]
+        noun = pool[id_ % len(pool)]
         if animal:
             return f"{animal} {noun} in {color}"
         return f"{color} {noun} No.{id_}"

← 4fbb6e7 drunk-animals quality purge — unpublish 513 'too abstract' d  ·  back to Wallco Ai  ·  pdp variants: clamp prev link to id>=1 (10 variants) + schem 3e32b5f →