← back to Wallco Ai
generator: log gate rejections to data/logs/gate-rejections.jsonl (close orphan provenance gap)
dbe44646aea81d24fc9ed07a23b818db76dfc519 · 2026-06-09 13:25:24 -0700 · Steve Abrams
When the ghost/seamless/frame-overlay gate rejects a tile after its retry, the
loop continued WITHOUT a DB insert, leaving an orphan PNG with no recorded
reason. Now each skip appends {ts,seed,file,gate,reason,category,kind} so the
wallco-live-viewer can name the actual gate instead of inferring 'gate-rejected'
from absence-of-row. Append-only; logging failures never block generation.
Files touched
M scripts/generate_designs.js
Diff
commit dbe44646aea81d24fc9ed07a23b818db76dfc519
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 9 13:25:24 2026 -0700
generator: log gate rejections to data/logs/gate-rejections.jsonl (close orphan provenance gap)
When the ghost/seamless/frame-overlay gate rejects a tile after its retry, the
loop continued WITHOUT a DB insert, leaving an orphan PNG with no recorded
reason. Now each skip appends {ts,seed,file,gate,reason,category,kind} so the
wallco-live-viewer can name the actual gate instead of inferring 'gate-rejected'
from absence-of-row. Append-only; logging failures never block generation.
---
scripts/generate_designs.js | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/scripts/generate_designs.js b/scripts/generate_designs.js
index 3f90722..35c14ff 100644
--- a/scripts/generate_designs.js
+++ b/scripts/generate_designs.js
@@ -28,6 +28,29 @@ fs.mkdirSync(OUT, { recursive: true });
const BACKEND = process.env.GEN_BACKEND || 'stub';
+// ── Gate-rejection audit log (2026-06-09) ──────────────────────────────────
+// When a quality gate (ghost / seamless / frame-overlay) rejects a tile after
+// its retry, the loop `continue`s WITHOUT a DB insert — the PNG is orphaned on
+// disk with no provenance. Record WHICH gate killed it + the reason here, so the
+// wallco-live-viewer's "gate-rejected · no DB row" cards can name the actual gate
+// instead of inferring it from absence-of-row. Append-only JSONL keyed by the
+// same seed/filename the viewer reads. Logging failures never block generation.
+const GATE_REJECT_LOG = path.join(ROOT, 'data', 'logs', 'gate-rejections.jsonl');
+function logGateRejection({ seed, localPath, gate, reason, category, kind }) {
+ try {
+ fs.mkdirSync(path.dirname(GATE_REJECT_LOG), { recursive: true });
+ fs.appendFileSync(GATE_REJECT_LOG, JSON.stringify({
+ ts: new Date().toISOString(),
+ seed: seed != null ? String(seed) : null,
+ file: localPath ? path.basename(localPath) : null,
+ gate,
+ reason: reason || null,
+ category: category || null,
+ kind: kind || null,
+ }) + '\n');
+ } catch (e) { console.warn(' ⚠ gate-rejection log failed:', e.message); }
+}
+
// ── Aesthetic direction (Steve 2026-05-19) ─────────────────────────────────
// Tone-on-tone, high-fashion. Bright neon and >4-distinct-hue palettes are
// purged at the catalog level (scripts/purge-neon-and-multicolor.js) AND
@@ -821,6 +844,9 @@ async function main() {
const r2 = await verifyNoGhostLayer(outPath).catch(e => e);
if (r2 && r2.code === 'GHOST_LAYER_DETECTED') {
console.warn(` ✗ ghost-layer persists after retry — skipping #${seed}`);
+ logGateRejection({ seed, localPath: outPath, gate: 'ghost-layer',
+ reason: (r2.detector_result && r2.detector_result.reason) || r2.message,
+ category: opt.category, kind: opt.kind });
continue;
}
console.log(` ✓ retry clean`);
@@ -874,6 +900,10 @@ async function main() {
const r2 = await verifySeamless(outPath, { tolerance, category: opt.category }).catch(e => e);
if (r2 && r2.code === 'SEAMLESS_DEFECT') {
console.warn(` ✗ still not seamless after retry — skipping #${seed}`);
+ const rdr = r2.detector_result || {};
+ logGateRejection({ seed, localPath: outPath, gate: 'seamless-tile',
+ reason: `${rdr.code || 'SEAMLESS_DEFECT'} tb=${rdr.top_bottom_diff} lr=${rdr.left_right_diff}`,
+ category: opt.category, kind: opt.kind });
continue;
}
console.log(` ✓ seamless after retry`);
@@ -911,6 +941,9 @@ async function main() {
const r2 = await verifyNoFrameOverlay(outPath, { category: opt.category }).catch(e => e);
if (r2 && r2.code === 'FRAME_OVERLAY_DETECTED') {
console.warn(` ✗ frame-overlay persists after retry — skipping #${seed}`);
+ logGateRejection({ seed, localPath: outPath, gate: 'frame-overlay',
+ reason: (r2.detector_result && r2.detector_result.reason) || r2.message,
+ category: opt.category, kind: opt.kind });
continue;
}
console.log(` ✓ frame-overlay clean after retry`);
← afa4976 cleanup: manifest of 14,632 May gate-rejected orphan designs
·
back to Wallco Ai
·
purge-orphan-pngs: reclaim gen-time orphan PNGs (no DB row) eedbd24 →