[object Object]

← back to Wallco Ai

harden settlement vision fallback (debugger pass): reject non-boolean 'violates' from Gemini→fall through; clamp partial-JSON ollama results to NEEDS REVIEW (close silent false-OK on garbled output)

a3e804860191e6fe845185a31f79241c224fb86a · 2026-06-09 16:03:01 -0700 · Steve

Files touched

Diff

commit a3e804860191e6fe845185a31f79241c224fb86a
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jun 9 16:03:01 2026 -0700

    harden settlement vision fallback (debugger pass): reject non-boolean 'violates' from Gemini→fall through; clamp partial-JSON ollama results to NEEDS REVIEW (close silent false-OK on garbled output)
---
 scripts/settlement_postgen_vision_check.js | 34 ++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/scripts/settlement_postgen_vision_check.js b/scripts/settlement_postgen_vision_check.js
index 84f9d9f..b026ea7 100644
--- a/scripts/settlement_postgen_vision_check.js
+++ b/scripts/settlement_postgen_vision_check.js
@@ -143,7 +143,15 @@ async function ollamaVision(b64, prompt) {
         logGemini(j, { app: 'wallco-ai', note: 'settlement-postgen-vision', model: GEMINI_MODEL });
       } catch {}
       const text = j.candidates?.[0]?.content?.parts?.find(p => p.text)?.text;
-      result = parseJsonLoose(text);
+      const parsed = parseJsonLoose(text);
+      // Integrity check: if `violates` is not a boolean the response is structurally
+      // incomplete (garbled/truncated model output). Treat as a failed Gemini parse
+      // and fall through to the local ollama fallback rather than silently returning OK.
+      if (parsed && typeof parsed.violates === 'boolean') {
+        result = parsed;
+      } else if (parsed) {
+        console.error(`Gemini returned parseable JSON but missing boolean 'violates' field — falling back to local ollama vision`);
+      }
     } else {
       console.error(`Gemini HTTP ${r.status}: ${(await r.text()).slice(0, 200)} — falling back to local ollama vision`);
     }
@@ -164,15 +172,29 @@ async function ollamaVision(b64, prompt) {
   const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
   if (!result) { console.error('both Gemini and local ollama vision unavailable — fail-closed'); process.exit(1); }
 
-  // CLAMP: a LOCAL-model "violation" is advisory, not authoritative. Local
+  // CLAMP: a LOCAL-model verdict is advisory, not authoritative. Local
   // vision (gemma3/llava) is good enough to CLEAR a clean design (OK) but can
   // err on positives — so never let it drive a destructive BLOCK/unpublish.
   // Downgrade a local-fallback violation to NEEDS REVIEW (sweep leaves those
   // published + flagged); only Gemini can produce a sweep-triggering BLOCK.
-  if (source.startsWith('ollama') && result && result.violates) {
-    result.violates = false;
-    result.needsReview = true;
-    result.reasoning = '[local-vision fallback flagged a possible violation — downgraded to NEEDS REVIEW pending authoritative Gemini re-check] ' + (result.reasoning || '');
+  //
+  // Also handles the partial-JSON case: if ollama returned a parsed object but
+  // `violates` is not a boolean (missing/null/undefined from a truncated response),
+  // the verdict is indeterminate — treat as NEEDS REVIEW rather than silently OK.
+  // A missing `violates` field means the model didn't reach a conclusion; it is
+  // NOT equivalent to "clean".
+  if (source.startsWith('ollama') && result) {
+    if (result.violates === true) {
+      result.violates = false;
+      result.needsReview = true;
+      result.reasoning = '[local-vision fallback flagged a possible violation — downgraded to NEEDS REVIEW pending authoritative Gemini re-check] ' + (result.reasoning || '');
+    } else if (typeof result.violates !== 'boolean') {
+      // Partial/truncated JSON from local model — missing the decisive field.
+      // Cannot treat as clean; flag for authoritative Gemini re-check.
+      result.violates = false;
+      result.needsReview = true;
+      result.reasoning = '[local-vision fallback returned incomplete JSON (no boolean violates field) — flagged NEEDS REVIEW pending authoritative Gemini re-check] ' + (result.reasoning || '');
+    }
   }
 
   console.log('\n=== SETTLEMENT POST-GEN VISION CHECK ===');

← a717efc feat(design-curator): 🛋 Room setting button — generate room  ·  back to Wallco Ai  ·  deploy: ship settlement vision-check + tick-guard to prod (h d2decec →