[object Object]

← back to Groundworks Activation

auto-save: 2026-07-22T07:42:20 (2 files) — data/ scripts/

9d7aad8f68eb32818957b40323688ba8eab33435 · 2026-07-22 07:42:29 -0700 · Steve Abrams

Files touched

Diff

commit 9d7aad8f68eb32818957b40323688ba8eab33435
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 22 07:42:29 2026 -0700

    auto-save: 2026-07-22T07:42:20 (2 files) — data/ scripts/
---
 data/settlement-audit.json   | 122 +++++++++++++++++++++++++++++++++++++++++++
 scripts/settlement-vision.py |  75 ++++++++++++++++++++++++++
 2 files changed, 197 insertions(+)

diff --git a/data/settlement-audit.json b/data/settlement-audit.json
new file mode 100644
index 0000000..4001684
--- /dev/null
+++ b/data/settlement-audit.json
@@ -0,0 +1,122 @@
+[
+  {
+    "mfr_sku": "GWP-3752.101.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Bunny Wall Small Wp - Ivory"
+  },
+  {
+    "mfr_sku": "GWP-3746.712.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Flutter Sisal - Sunset"
+  },
+  {
+    "mfr_sku": "GWP-3752.8.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Bunny Wall Small Wp - Black"
+  },
+  {
+    "mfr_sku": "GWP-3748.3.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hula Sisal - Sage"
+  },
+  {
+    "mfr_sku": "GWP-3748.7.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hula Sisal - Bloom"
+  },
+  {
+    "mfr_sku": "GWP-3746.194.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Flutter Sisal - Rainbow"
+  },
+  {
+    "mfr_sku": "GWP-3746.513.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Flutter Sisal - The Blues"
+  },
+  {
+    "mfr_sku": "GWP-3747.319.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hutch Patchwork Wp - Multi"
+  },
+  {
+    "mfr_sku": "GWP-3751.101.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Bunny Wall Wp - Ivory"
+  },
+  {
+    "mfr_sku": "GWP-3748.50.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hula Sisal - Navy"
+  },
+  {
+    "mfr_sku": "GWP-3751.8.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Bunny Wall Wp - Black"
+  },
+  {
+    "mfr_sku": "GWP-3748.8.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hula Sisal - Ink"
+  },
+  {
+    "mfr_sku": "GWP-3750.816.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hutch Raffia - Ink"
+  },
+  {
+    "mfr_sku": "GWP-3749.513.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hutch Ombre Paper - Blue"
+  },
+  {
+    "mfr_sku": "GWP-3749.719.0",
+    "verdict": "BLOCK",
+    "detectors": {
+      "error": "HTTP Error 404: Not Found"
+    },
+    "name": "Hutch Ombre Paper - Pink"
+  }
+]
\ No newline at end of file
diff --git a/scripts/settlement-vision.py b/scripts/settlement-vision.py
new file mode 100644
index 0000000..c2390f6
--- /dev/null
+++ b/scripts/settlement-vision.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+"""Settlement post-gen vision gate for Groundworks Hunt Slonem images.
+Runs Gemini 2.0 Flash on each image, extracting the 5 settlement detector booleans,
+then applies the settlement-verdict combinator: BLOCK only when full Part A
+(A1 directional foliage AND A2 open space AND A3 multiple ink colors) is satisfied
+AND a Part B element (banana/grape/BIRD/BUTTERFLY) is present, absent an acceptable carve-out.
+Rabbits/bunnies are NOT Part B prohibited elements.
+"""
+import os, sys, json, base64, urllib.request, time
+
+KEY = os.environ.get("GEMINI_API_KEY")
+if not KEY:
+    print("ERR: no GEMINI_API_KEY"); sys.exit(2)
+MODEL = "gemini-2.0-flash"
+URL = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL}:generateContent?key={KEY}"
+
+PROMPT = """You are a strict visual detector for a wallcovering settlement gate. Look ONLY at what is actually visible in this repeating pattern image. Answer as JSON with these exact boolean/string fields:
+{
+ "a1_directional_foliage": <true if there are leaves/fronds/foliage shown in MORE THAN ONE orientation across the repeat, else false>,
+ "a2_open_space": <true if there is visible negative/open space BETWEEN foliage motifs (not edge-to-edge coverage), else false>,
+ "a3_multiple_ink_colors": <true if the foliage/leaf layer uses more than one ink color (excluding background), else false>,
+ "partB_bananas": <true if bananas or banana pods visible>,
+ "partB_grapes": <true if grapes visible>,
+ "partB_birds": <true if birds visible>,
+ "partB_butterflies": <true if butterflies or moths visible>,
+ "acceptable_trunk_branch": <true if clearly represented tree trunks or branches visible>,
+ "primary_motif": "<one short phrase describing the main visible motif>"
+}
+Return ONLY the JSON, no prose."""
+
+def gemini(image_bytes, mime="image/jpeg"):
+    b64 = base64.b64encode(image_bytes).decode()
+    body = {"contents":[{"parts":[{"text":PROMPT},{"inline_data":{"mime_type":mime,"data":b64}}]}],
+            "generationConfig":{"temperature":0,"maxOutputTokens":400}}
+    req = urllib.request.Request(URL, data=json.dumps(body).encode(), headers={"Content-Type":"application/json"})
+    with urllib.request.urlopen(req, timeout=90) as r:
+        resp = json.load(r)
+    txt = resp["candidates"][0]["content"]["parts"][0]["text"].strip()
+    if txt.startswith("```"):
+        txt = txt.split("```")[1]
+        if txt.startswith("json"): txt = txt[4:]
+    return json.loads(txt.strip())
+
+def verdict(d):
+    partA = d["a1_directional_foliage"] and d["a2_open_space"] and d["a3_multiple_ink_colors"]
+    partB = d["partB_bananas"] or d["partB_grapes"] or d["partB_birds"] or d["partB_butterflies"]
+    if partA and partB and not d.get("acceptable_trunk_branch"):
+        return "BLOCK"
+    if partB and not partA:
+        # prohibited element present but not full-tropical composition -> defendant-favorable but flag
+        return "NEEDS REVIEW"
+    if partA and partB and d.get("acceptable_trunk_branch"):
+        return "NEEDS REVIEW"
+    return "OK"
+
+items = json.load(open(sys.argv[1]))
+out = []
+for it in items:
+    sku, url = it["mfr_sku"], it["image_url"]
+    try:
+        img = urllib.request.urlopen(url, timeout=60).read()
+        d = gemini(img)
+        v = verdict(d)
+    except Exception as e:
+        d = {"error": str(e)}; v = "BLOCK"  # unknown => BLOCK per hard rule
+    rec = {"mfr_sku": sku, "verdict": v, "detectors": d, "name": it.get("name")}
+    out.append(rec)
+    print(f"{v:14s} {sku:16s} {it.get('name','')} :: partB_birds={d.get('partB_birds')} partB_butterflies={d.get('partB_butterflies')} motif={d.get('primary_motif','')}")
+    time.sleep(0.4)
+
+json.dump(out, open(sys.argv[2],"w"), indent=2)
+n_block = sum(1 for r in out if r["verdict"]=="BLOCK")
+n_rev = sum(1 for r in out if r["verdict"]=="NEEDS REVIEW")
+n_ok = sum(1 for r in out if r["verdict"]=="OK")
+print(f"\nSUMMARY: OK={n_ok} NEEDS_REVIEW={n_rev} BLOCK={n_block}  (audit -> {sys.argv[2]})")

← 73b9407 initial scaffold  ·  back to Groundworks Activation  ·  Groundworks settlement vision gate: 12 OK (rabbits, not Part e609263 →