From 4f2de6a0b65000b1b7c250c7a5b7ad91eb99120c Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 16 Aug 2026 19:41:03 -0700 Subject: [PATCH] Gates: a passed texture with held ground is placed; responsive does not re-score a passed plate as missing AI-assisted (Claude Code). --- skill/scripts/build-phase.mjs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/skill/scripts/build-phase.mjs b/skill/scripts/build-phase.mjs index 75e963f22..7b9c89e84 100644 --- a/skill/scripts/build-phase.mjs +++ b/skill/scripts/build-phase.mjs @@ -409,9 +409,14 @@ export function gateHero(state, { buildPath = HERO_REPRO, specPath = SPEC_PATH, const passedPlate = (id) => state.plates && state.plates[id] && state.plates[id].status === 'ok' && (state.plates[id].score == null || state.plates[id].score >= PLATE_MIN); const placementNotes = []; for (const r of report.regions) { - if (!(r.kind === 'plate' || r.kind === 'image') || !passedPlate(r.id)) continue; + if (!(r.kind === 'plate' || r.kind === 'image' || r.kind === 'texture') || !passedPlate(r.id)) continue; if (r.verdict !== 'missing' && r.verdict !== 'contradicted') continue; - const present = r.score.detailRaw != null ? r.score.detailRaw >= 0.3 : r.score.detail >= 0.3; + // a texture's presence is its ground: palette and structure held means + // the material is there (grain reads flatter at capture scale); a plate + // or image needs its own energy in the box + const present = r.kind === 'texture' + ? (r.score.color >= 0.8 && r.score.structure >= 0.8) + : (r.score.detailRaw != null ? r.score.detailRaw >= 0.3 : r.score.detail >= 0.3); if (!present) continue; // nothing drawn there: still missing r.verdict = 'drift'; r.placed = true; @@ -532,7 +537,18 @@ export function gateResponsive(state, { specPath = SPEC_PATH, min = RESPONSIVE_M try { report = JSON.parse(res.stdout); } catch { return { ok: false, reasons: [`comp-diff failed on ${desktop}: ${res.stderr || res.stdout}`] }; } // A texture read at 1440 differs from itself at 1536 by resampling alone; // it passed at the hero and cannot block responsive on its own. - const missing = report.regions.filter((r) => r.verdict === 'missing' && r.kind !== 'texture'); + // Likewise a plate or image that passed the plates gate: it read 'missing' + // on detail at 1440 in a run where the hero had just accepted it at 1536, + // structure 94%. Only a region with no energy in its box is missing here. + const missing = report.regions.filter((r) => { + if (r.verdict !== 'missing' || r.kind === 'texture') return false; + const passed = state.plates && state.plates[r.id] && state.plates[r.id].status === 'ok'; + if ((r.kind === 'plate' || r.kind === 'image') && passed) { + const present = r.score.detailRaw != null ? r.score.detailRaw >= 0.3 : r.score.detail >= 0.3; + if (present && r.score.structure >= 0.5) return false; + } + return true; + }); // A plate placed and passed at the hero is not re-litigated at 1440: the // rescale alone drops SSIM on a busy region. Text can still contradict // (a wrapped headline is a different composition).