[object Object]

← back to Dw Pairs Well

SIMILAR_CLIP_DEFAULT one-switch flag; KAMATERA-GOLIVE.md paste bundle (discovery: Kamatera already hosts visual-search in dwphoto — no tailnet needed)

82d7d3ab99aa11f843fec031616248af076254fc · 2026-07-13 01:29:32 -0700 · Steve Abrams

Files touched

Diff

commit 82d7d3ab99aa11f843fec031616248af076254fc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 13 01:29:32 2026 -0700

    SIMILAR_CLIP_DEFAULT one-switch flag; KAMATERA-GOLIVE.md paste bundle (discovery: Kamatera already hosts visual-search in dwphoto — no tailnet needed)
---
 deploy/KAMATERA-GOLIVE.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 server.js                 | 10 ++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/deploy/KAMATERA-GOLIVE.md b/deploy/KAMATERA-GOLIVE.md
new file mode 100644
index 0000000..a81027b
--- /dev/null
+++ b/deploy/KAMATERA-GOLIVE.md
@@ -0,0 +1,58 @@
+# Kamatera go-live — CLIP coordinates + link guarantee (one paste per block)
+
+Discovery: Kamatera already hosts a visual-search stack at
+`/root/public-projects/dwphoto/visual-search` (embed-daemon.sh targets it; service on
+localhost :9914 with its OWN image_embeddings in Kamatera dw_unified). pairs-well's
+default `VISUAL_SEARCH_URL` is `http://127.0.0.1:9914`, so NO tailnet exposure is needed.
+
+## Block 1 — ship pairs-well (kills the bad links immediately)
+```sh
+cd ~/Projects/dw-pairs-well && bash ~/Projects/_shared/scripts/deploy.sh
+```
+Ships: ACTIVE+online_store_published gate on every suggestion path, no-store link
+responses, color+texture-locked CLIP engine, PUB_SQL schema-drift guard, engine flags.
+Boot log line to check: `[link-guarantee] online_store_published present — full ... gate on`
+(if it says MISSING, Kamatera's mirror lacks the column — tell Claude, the app still runs
+status-only). Zero UI changes.
+
+## Block 2 — update Kamatera's visual-search + turn CLIP on (run on Mac2)
+```sh
+# push the updated service (adds /pairwise + the ACTIVE+published handle join) + gap embedder
+rsync -az ~/Projects/dw-photo-capture/visual-search/search_service.py \
+          ~/Projects/dw-photo-capture/visual-search/embed_shopify_gap.py \
+          root@45.61.58.125:/root/public-projects/dwphoto/visual-search/
+ssh root@45.61.58.125 '
+  set -e
+  cd /root/public-projects/dwphoto/visual-search
+  # is the service running? restart whatever pm2 name owns :9914
+  pm2 restart $(pm2 jlist | python3 -c "import sys,json;[print(p[\"name\"]) for p in json.load(sys.stdin) if \"visual\" in p[\"name\"] or \"9914\" in str(p.pm2_env if False else p)]" 2>/dev/null || echo visual-search) || true
+  sleep 20 && curl -s http://127.0.0.1:9914/health
+  # embed the shopify-only gap on Kamatera (resumable; ~30-60 min first run)
+  export DW_UNIFIED_DB="$(grep ^DW_UNIFIED_DB= ../.env | cut -d= -f2-)"
+  nohup nice -n 15 python3 embed_shopify_gap.py --workers 16 > gap-embed.log 2>&1 &
+  # flip CLIP on for pairs + similar
+  cd /root/Projects/dw-pairs-well
+  grep -q PAIRS_CLIP_DEFAULT .env || printf "PAIRS_CLIP_DEFAULT=1\nSIMILAR_CLIP_DEFAULT=1\n" >> .env
+  pm2 restart dw-pairs-well
+'
+```
+Caveats Claude could NOT pre-verify (prod SSH is Steve-gated):
+- the pm2 process name owning :9914 on Kamatera (the restart line guesses; `pm2 ls | grep -i visual` to find it)
+- whether Kamatera's dwphoto has the fine-tuned dw_clip_ft.pt (its index is internally
+  consistent either way — /similar works regardless)
+- whether Kamatera dw_unified has online_store_published (Block 1's boot log answers it)
+
+## Block 3 — prove it (run on Mac2, after Block 1)
+```sh
+cd ~/Projects/dw-pairs-well
+BASE=https://pairs.designerwallcoverings.com N=8 bash tools/live-link-check.sh
+```
+Expect: `LINK GUARANTEE: PASS`. Or just tell Claude "verify live" and it runs this.
+
+## Mac2 nightly coverage top-up (optional paste)
+```sh
+chmod +x ~/Projects/dw-photo-capture/visual-search/embed-nightly-mac2.sh
+cp ~/Projects/dw-photo-capture/visual-search/com.steve.visual-search-embed-nightly.plist ~/Library/LaunchAgents/
+launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.steve.visual-search-embed-nightly.plist
+```
+Runs 4:20am daily: embeds new products (both embedders, resumable) + hot-reloads the index.
diff --git a/server.js b/server.js
index 71aa948..2a1128a 100644
--- a/server.js
+++ b/server.js
@@ -25,6 +25,9 @@ const VISUAL_SEARCH_URL = process.env.VISUAL_SEARCH_URL || 'http://127.0.0.1:991
 // the visual-search service is confirmed reachable from the serving host. ?engine=tag
 // is an explicit per-request override that force-disables the blend even when default-on.
 const PAIRS_CLIP_DEFAULT = /^(1|true|on)$/i.test(process.env.PAIRS_CLIP_DEFAULT || '');
+// Same one-switch for /api/similar: SIMILAR_CLIP_DEFAULT=1 makes the CLIP color+texture
+// engine the default for all callers (per-request ?engine=tag still forces tag).
+const SIMILAR_CLIP_DEFAULT = /^(1|true|on)$/i.test(process.env.SIMILAR_CLIP_DEFAULT || '');
 // Latency guardrail: a short per-call timeout + a circuit-breaker so an unreachable/slow
 // visual-search service never adds more than one slow call per cooldown window to customer
 // traffic. On any failure we "trip" and skip the service for CLIP_COOLDOWN_MS.
@@ -1044,9 +1047,12 @@ app.get('/api/similar', async (req, res) => {
     if (!source) return res.status(404).json({ ok: false, error: 'source not found' });
 
     const requestedK = Math.max(1, Math.min(24, parseInt(req.query.limit, 10) || 12));
-    const engine = (req.query.engine === 'clip') ? 'clip' : 'tag';
+    // CLIP when explicitly requested (?engine=clip) OR when SIMILAR_CLIP_DEFAULT is on
+    // and the caller didn't force ?engine=tag. Same one-switch pattern as pairs.
+    const engine = (req.query.engine === 'clip' || (SIMILAR_CLIP_DEFAULT && req.query.engine !== 'tag'))
+      ? 'clip' : 'tag';
 
-    // CLIP engine (opt-in): image-embedding nearest-neighbour, no tag dependency.
+    // CLIP engine: color+texture-locked image-embedding nearest-neighbour, no tag dependency.
     let top = null, usedEngine = 'tag';
     if (engine === 'clip') {
       top = await clipSimilarTop(source, requestedK);   // null → service down / sku not embedded

← 2805347 5x: final report — sweep 5 clean at cap  ·  back to Dw Pairs Well  ·  deploy/fix-osp-kamatera.sh — sync online_store_published fla 6145281 →