[object Object]

← back to Wallco Ai

mid-heal-preview: $0 SDXL grid-leak fix sample preview

e30db7df604a247e267b6d65b1bab45807e3b64b · 2026-05-26 08:17:33 -0700 · Steve Abrams

20-design experiment with PIL Gaussian-band-blur (BAND_PX=12, SIGMA=4.0)
applied to the H/2 and V/2 midlines of mids-only FAILs from the edges
sweep. Result: 20/20 improved, 9/20 → PASS, 11/20 → WARN, 0 stayed FAIL.
Avg mids ΔE 17.10 → 3.44 (80% reduction). No design got worse.

This is a free replacement for the planned $293 Gemini-edit run on the
7,333 SDXL grid-leak cohort. New admin surface lets Steve eyeball-verify
the 24-px blur band isn't visually obtrusive before scaling.

/admin/mid-heal-preview                  — side-by-side gallery
/api/admin/mid-heal-preview/sample       — JSON from /tmp/seam-heal-experiment.json

Heal-band overlay toggle highlights the red regions where the blur was
applied — everything outside is untouched. Composition preserved.

Production batch tool ships once Steve approves the visual quality.
Standing rule "round-1 outputs are sacred" — the batch tool will
backup originals as __preseam.png and INSERT new spoon_all_designs rows
with generator='pil-mid-heal' + parent_design_id=source, mirroring the
fix-seam pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit e30db7df604a247e267b6d65b1bab45807e3b64b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 26 08:17:33 2026 -0700

    mid-heal-preview: $0 SDXL grid-leak fix sample preview
    
    20-design experiment with PIL Gaussian-band-blur (BAND_PX=12, SIGMA=4.0)
    applied to the H/2 and V/2 midlines of mids-only FAILs from the edges
    sweep. Result: 20/20 improved, 9/20 → PASS, 11/20 → WARN, 0 stayed FAIL.
    Avg mids ΔE 17.10 → 3.44 (80% reduction). No design got worse.
    
    This is a free replacement for the planned $293 Gemini-edit run on the
    7,333 SDXL grid-leak cohort. New admin surface lets Steve eyeball-verify
    the 24-px blur band isn't visually obtrusive before scaling.
    
    /admin/mid-heal-preview                  — side-by-side gallery
    /api/admin/mid-heal-preview/sample       — JSON from /tmp/seam-heal-experiment.json
    
    Heal-band overlay toggle highlights the red regions where the blur was
    applied — everything outside is untouched. Composition preserved.
    
    Production batch tool ships once Steve approves the visual quality.
    Standing rule "round-1 outputs are sacred" — the batch tool will
    backup originals as __preseam.png and INSERT new spoon_all_designs rows
    with generator='pil-mid-heal' + parent_design_id=source, mirroring the
    fix-seam pattern.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 public/admin/mid-heal-preview.html | 214 +++++++++++++++++++++++++++++++++++++
 server.js                          |  37 +++++++
 2 files changed, 251 insertions(+)

diff --git a/public/admin/mid-heal-preview.html b/public/admin/mid-heal-preview.html
new file mode 100644
index 0000000..f7eb322
--- /dev/null
+++ b/public/admin/mid-heal-preview.html
@@ -0,0 +1,214 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<meta name="robots" content="noindex,nofollow">
+<title>Mid-Seam-Heal Preview — wallco.ai admin</title>
+<style>
+  :root {
+    --ink:#1f1808; --line:#d8d0c0; --gold:#c9a14b;
+    --bg:#fbf8f1; --card:#fff; --faint:#7a6e5a;
+    --green:#1f6a2c; --red:#b3261e; --orange:#c0660b;
+    --sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
+    --serif:'Playfair Display','Didot',Georgia,serif;
+  }
+  * { box-sizing:border-box; }
+  body { margin:0; background:var(--bg); color:var(--ink); font:14px var(--sans); }
+  header {
+    padding:14px 24px; border-bottom:1px solid var(--line); background:#fff;
+    display:flex; gap:16px; align-items:baseline; position:sticky; top:0; z-index:5;
+  }
+  header h1 { font:400 22px/1.2 var(--serif); margin:0; }
+  header .meta { color:var(--faint); font-size:12px; }
+  header .summary { margin-left:auto; font:600 12px ui-monospace,Menlo,monospace; color:var(--ink); }
+  header .summary .pass { color:var(--green); }
+  header .summary .warn { color:var(--orange); }
+  header .summary .fail { color:var(--red); }
+  main { max-width:1400px; margin:0 auto; padding:18px; }
+
+  .controls {
+    display:flex; gap:14px; align-items:center; padding:11px 14px;
+    background:#fff; border:1px solid var(--line); border-radius:8px;
+    margin-bottom:14px; font-size:12px;
+  }
+  .controls label { font:600 10.5px var(--sans); letter-spacing:.16em;
+                    text-transform:uppercase; color:var(--faint); }
+  .controls .toggle { display:flex; align-items:center; gap:6px; cursor:pointer; }
+  .controls .toggle input { margin:0; }
+
+  .pair {
+    background:#fff; border:1px solid var(--line); border-radius:8px;
+    margin-bottom:18px; padding:14px;
+  }
+  .pair-header {
+    display:flex; justify-content:space-between; align-items:baseline;
+    margin-bottom:10px;
+  }
+  .pair-id {
+    font:700 14px ui-monospace,Menlo,monospace; color:var(--ink);
+  }
+  .pair-stats {
+    font:600 12px ui-monospace,Menlo,monospace; color:var(--faint);
+  }
+  .pair-stats .v-before { color:var(--red); }
+  .pair-stats .v-after.pass { color:var(--green); }
+  .pair-stats .v-after.warn { color:var(--orange); }
+  .pair-stats .v-after.fail { color:var(--red); }
+
+  .duo {
+    display:grid; grid-template-columns:1fr 1fr; gap:12px;
+  }
+  .duo .panel { position:relative; }
+  .duo .panel img {
+    width:100%; aspect-ratio:1; object-fit:cover;
+    border:1px solid var(--line); border-radius:6px;
+    background:#f3eee2;
+  }
+  .duo .panel.show-bands img {
+    /* highlight the heal band */
+  }
+  .duo .panel.show-bands::after {
+    content:''; position:absolute; inset:0;
+    background:
+      linear-gradient(transparent calc(50% - 12px), rgba(255,52,52,.18) calc(50% - 12px), rgba(255,52,52,.18) calc(50% + 12px), transparent calc(50% + 12px)),
+      linear-gradient(90deg, transparent calc(50% - 12px), rgba(255,52,52,.18) calc(50% - 12px), rgba(255,52,52,.18) calc(50% + 12px), transparent calc(50% + 12px));
+    border-radius:6px;
+    pointer-events:none;
+  }
+  .duo .panel-label {
+    position:absolute; top:8px; left:8px;
+    background:rgba(0,0,0,.7); color:#fff;
+    font:700 9px var(--sans); letter-spacing:.12em; text-transform:uppercase;
+    padding:3px 7px; border-radius:3px;
+  }
+  .duo .panel-de {
+    position:absolute; bottom:8px; right:8px;
+    background:rgba(0,0,0,.65); color:#fff;
+    font:700 10px ui-monospace,Menlo,monospace;
+    padding:3px 7px; border-radius:3px;
+  }
+  .duo .panel.before .panel-de { background:rgba(179,38,30,.85); }
+  .duo .panel.after  .panel-de { background:rgba(31,106,44,.85); }
+
+  .verdict-pill {
+    display:inline-block;
+    font:700 9.5px var(--sans); letter-spacing:.14em; text-transform:uppercase;
+    padding:3px 8px; border-radius:3px;
+    color:#fff;
+  }
+  .verdict-pill.PASS { background:var(--green); }
+  .verdict-pill.WARN { background:var(--orange); }
+  .verdict-pill.FAIL { background:var(--red); }
+
+  .loading { text-align:center; padding:40px; color:var(--faint); }
+
+  .decision {
+    background:var(--ink); color:#fff;
+    padding:16px 24px; border-radius:8px;
+    margin-top:20px; text-align:center;
+  }
+  .decision h3 { margin:0 0 8px; font:400 18px var(--serif); }
+  .decision p  { margin:0 0 12px; color:#dcd0bb; font-size:13px; }
+  .decision .btn {
+    background:var(--gold); color:#fff; border:0; padding:10px 22px;
+    border-radius:4px; cursor:pointer; margin:0 6px;
+    font:600 11.5px var(--sans); letter-spacing:.12em; text-transform:uppercase;
+  }
+  .decision .btn.no { background:#555; }
+</style>
+</head>
+<body>
+<header>
+  <h1>Mid-Seam-Heal Preview</h1>
+  <span class="meta">20-sample · BAND=12px · SIGMA=4.0 · before vs after</span>
+  <div class="summary" id="summary">loading…</div>
+</header>
+
+<main>
+  <div class="controls">
+    <label class="toggle">
+      <input type="checkbox" id="show-bands">
+      Highlight heal bands (red overlay at H/2 and V/2)
+    </label>
+    <span style="margin-left:auto; color:var(--faint); font-size:11px;">
+      The red bands show the 24px region (12px each side of the midline) where
+      Gaussian blur σ=4 was applied. Everything outside the bands is untouched.
+    </span>
+  </div>
+
+  <div id="pairs"><div class="loading">loading sample…</div></div>
+
+  <div class="decision">
+    <h3>Eyeball check — does the blur band look acceptable?</h3>
+    <p>If yes, scale to all 7,333 mids-only FAILs for $0 (new spoon_all_designs rows,
+       round-1 originals preserved as __preseam.png backup).</p>
+    <p style="font-size:11.5px; color:var(--gold)">
+      This page is read-only. Tell Claude in chat to scale or to retune
+       (e.g. "tighter band" / "less blur" / "different sigma").
+    </p>
+  </div>
+</main>
+
+<script>
+fetch('/api/admin/mid-heal-preview/sample')
+  .then(r => r.json())
+  .then(data => {
+    if (!data.ok) {
+      document.getElementById('pairs').innerHTML =
+        `<div class="loading">error: ${data.error || 'unknown'}</div>`;
+      return;
+    }
+    const rows = data.items || [];
+    const passN = rows.filter(r => r.post_v === 'PASS').length;
+    const warnN = rows.filter(r => r.post_v === 'WARN').length;
+    const failN = rows.filter(r => r.post_v === 'FAIL').length;
+    document.getElementById('summary').innerHTML =
+      `n=${rows.length}  ` +
+      `<span class="fail">${rows.length} FAIL</span> → ` +
+      `<span class="pass">${passN} PASS</span> + ` +
+      `<span class="warn">${warnN} WARN</span> + ` +
+      `<span class="fail">${failN} still FAIL</span>`;
+
+    document.getElementById('pairs').innerHTML = rows.map(r => `
+      <div class="pair">
+        <div class="pair-header">
+          <span class="pair-id">#${r.id}</span>
+          <span class="pair-stats">
+            mids ${r.pre_mids.toFixed(1)} → ${r.post_mids.toFixed(1)} &nbsp;·&nbsp;
+            max ${r.pre_max.toFixed(1)} → ${r.post_max.toFixed(1)} &nbsp;·&nbsp;
+            <span class="verdict-pill ${r.pre_v}">${r.pre_v}</span>
+            →
+            <span class="verdict-pill ${r.post_v}">${r.post_v}</span>
+          </span>
+        </div>
+        <div class="duo">
+          <div class="panel before">
+            <span class="panel-label">Before (source)</span>
+            <img src="${r.before_url}" loading="lazy" alt="before #${r.id}">
+            <span class="panel-de">ΔE ${r.pre_max.toFixed(1)}</span>
+          </div>
+          <div class="panel after">
+            <span class="panel-label">After (heal)</span>
+            <img src="${r.after_url}" loading="lazy" alt="after #${r.id}">
+            <span class="panel-de">ΔE ${r.post_max.toFixed(1)}</span>
+          </div>
+        </div>
+      </div>
+    `).join('');
+
+    const cb = document.getElementById('show-bands');
+    function applyBands() {
+      document.querySelectorAll('.duo .panel').forEach(p => {
+        p.classList.toggle('show-bands', cb.checked);
+      });
+    }
+    cb.addEventListener('change', applyBands);
+  })
+  .catch(err => {
+    document.getElementById('pairs').innerHTML =
+      `<div class="loading">fetch failed: ${err.message}</div>`;
+  });
+</script>
+</body>
+</html>
diff --git a/server.js b/server.js
index 8eeddba..909ba06 100644
--- a/server.js
+++ b/server.js
@@ -1080,6 +1080,43 @@ app.get('/admin/elements', (req, res) => {
   res.sendFile(path.join(__dirname, 'public', 'admin', 'elements.html'));
 });
 
+// ── /admin/mid-heal-preview — side-by-side before/after for the 20-design
+// SDXL grid-leak repair experiment. Gates the decision to scale the
+// PIL-only $0 mid-seam-blend to all 7,333 mids-only FAILs.
+app.get('/admin/mid-heal-preview', (req, res) => {
+  if (!isAdmin(req)) return res.status(404).type('html').send('<h1>404</h1>');
+  res.sendFile(path.join(__dirname, 'public', 'admin', 'mid-heal-preview.html'));
+});
+
+app.get('/api/admin/mid-heal-preview/sample', (req, res) => {
+  if (!isAdmin(req)) return res.status(404).json({ error: 'not found' });
+  try {
+    const ledgerPath = '/tmp/seam-heal-experiment.json';
+    if (!fs.existsSync(ledgerPath)) {
+      return res.json({ ok: false, error: 'ledger missing — run seam_heal_experiment.py first' });
+    }
+    const rows = JSON.parse(fs.readFileSync(ledgerPath, 'utf8'));
+    const items = rows.map(r => {
+      const fp = r.fixed_path || '';
+      // fixed_path is data/generated/<name>.__midheal.png — serve via /designs/img/<basename>
+      const after_url = fp ? '/designs/img/' + path.basename(fp) : null;
+      // before_url = source served by-id (route handles missing-from-cache)
+      const before_url = `/designs/img/by-id/${r.id}`;
+      return {
+        id: r.id,
+        pre_mids: r.pre_mids, post_mids: r.post_mids,
+        pre_edges: r.pre_edges, post_edges: r.post_edges,
+        pre_max: r.pre_max,   post_max: r.post_max,
+        pre_v: r.pre_v,       post_v: r.post_v,
+        before_url, after_url,
+      };
+    });
+    res.json({ ok: true, items });
+  } catch (err) {
+    res.status(500).json({ ok: false, error: err.message });
+  }
+});
+
 // Serve baked element derivatives. These live outside the public
 // /designs/img/ tree so they can be cleared without touching source tiles.
 app.use('/elements/img', express.static(

← 50890a3 elements skill: /admin/elements browse UI + bake-at-ingest p  ·  back to Wallco Ai  ·  gitignore: exclude data/elements (6GB), data/rooms (141MB), 3190409 →