← 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
A data/settlement-audit.jsonA scripts/settlement-vision.py
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 →