mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
Hero readings: sibling regions fold into one line; ink colour only on type at cap 16+
A build reached hero 81% and stalled on eight staff rows read one at a time (and both ways on ink colour). The session asked the user and was told to build as written; the force was legitimate and recorded. AI-assisted (Claude Code).
This commit is contained in:
@@ -523,7 +523,16 @@ export function gateHero(state, { buildPath = HERO_REPRO, specPath = SPEC_PATH,
|
||||
// the numbers are the edit list: keep it short enough to act on in one
|
||||
// pass (the worst first: size, then lines, then colour and place)
|
||||
const order = (f) => (/cap height/.test(f) ? 0 : /lines? in the build/.test(f) ? 1 : /heavier|lighter/.test(f) ? 2 : /ink is/.test(f) ? 3 : 4);
|
||||
const text = [...readings.text].sort((a, b) => order(a) - order(b));
|
||||
// sibling regions (row-1 ... row-8, item-a / item-b) with the same kind
|
||||
// of finding are one edit: fold them into one line naming the siblings
|
||||
const folded = new Map();
|
||||
for (const f of readings.text) {
|
||||
const m = /^text ([a-z0-9]+(?:-[a-z0-9]+)*?)(?:-(?:\d+|[a-z]))?: (cap height|\d+ lines? in the build|the face renders|ink is|its first line|it starts|line pitch)/i.exec(f);
|
||||
const key = m ? `${m[1]}|${m[2].replace(/\d+/g, 'N')}` : f;
|
||||
if (!folded.has(key)) folded.set(key, { first: f, ids: [] });
|
||||
const idm = /^text ([^:]+):/.exec(f); if (idm) folded.get(key).ids.push(idm[1]);
|
||||
}
|
||||
const text = [...folded.values()].map((v) => (v.ids.length > 1 ? `${v.first} (also ${v.ids.slice(1).join(', ')})` : v.first)).sort((a, b) => order(a) - order(b));
|
||||
// A reading that has come back unchanged three attempts running is one
|
||||
// the session is not acting on (or cannot: a measured "rule" that is
|
||||
// really an underline the layout does not have). It stays in the message
|
||||
|
||||
@@ -81,11 +81,15 @@ export function textRegionCheck(region, compCrop, buildCrop, { capTol = 0.22, mi
|
||||
if (r > 1.25) findings.push(`text ${region.id}: the face renders ${Math.round((r - 1) * 100)}% heavier than the comp's (ink density ${bfp.densTall.toFixed(2)} vs ${comp.densTall.toFixed(2)}); drop a weight step or use the ranked face`);
|
||||
else if (r < 0.75) findings.push(`text ${region.id}: the face renders ${Math.round((1 - r) * 100)}% lighter than the comp's (ink density ${bfp.densTall.toFixed(2)} vs ${comp.densTall.toFixed(2)}); raise a weight step or use the ranked face`);
|
||||
}
|
||||
// colour: dominant ink of each crop
|
||||
const ca = inkColor(compCrop), cb = inkColor(buildCrop);
|
||||
if (ca && cb && ca.ink && cb.ink) {
|
||||
const d = deltaE(ca.ink.lab, cb.ink.lab);
|
||||
if (d > 22) findings.push(`text ${region.id}: ink is ${cb.ink.hex} in the build, ${ca.ink.hex} in the comp; use the comp's colour`);
|
||||
// colour: dominant ink of each crop. Small type on a ruled or grainy
|
||||
// ground (a track row across staff lines at cap 14) has no reliable ink
|
||||
// cluster; the reading fired both ways on neighbouring rows of one list.
|
||||
if (comp.capHeightPx >= 16) {
|
||||
const ca = inkColor(compCrop), cb = inkColor(buildCrop);
|
||||
if (ca && cb && ca.ink && cb.ink) {
|
||||
const d = deltaE(ca.ink.lab, cb.ink.lab);
|
||||
if (d > 22) findings.push(`text ${region.id}: ink is ${cb.ink.hex} in the build, ${ca.ink.hex} in the comp; use the comp's colour`);
|
||||
}
|
||||
}
|
||||
// vertical placement inside the box: top of ink
|
||||
const ba = inkBox(compCrop), bb = inkBox(buildCrop);
|
||||
|
||||
Reference in New Issue
Block a user