1863 Commits
Author SHA1 Message Date
77a2eae861 Add IMPECCABLE_CACHE_ROOT to relocate hook state out of project roots (#422)
Honor an optional IMPECCABLE_CACHE_ROOT env var in getCachePath() /
getPendingPath(): when set, hook.cache.json and hook.pending.json land
under $IMPECCABLE_CACHE_ROOT/<project-slug>/ (slug = project path with
[:\/.] mapped to hyphens, mirroring Claude Code's ~/.claude/projects/
convention). Unset or blank env keeps stock project-local behavior.
User-authored config (config.json, config.local.json, design.json)
deliberately stays project-local - only disposable state relocates.

Also clears ambient IMPECCABLE_CACHE_ROOT at the top of hook.test.mjs so
a developer running the suite with the redirect active still gets
deterministic stock-path assertions; the new suite sets and restores the
var explicitly.

Prepared with AI assistance (Claude Code) under direction of
0xDarkMatter, per the maintainer-approved issue #422.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 15:14:49 +05:00
github-actions[bot] 0c2517884d Sync generated provider output 2026-08-28 10:02:05 +00:00
Paul BakausandAbdul Wahab 08b03e8763 Centralize live path glob matching
AI-assisted change prepared by Codex under scheduled architecture-simplification authorization from maintainer pbakaus.
2026-08-28 15:01:21 +05:00
Paul BakausandAbdul Wahab 3df4c4b10d Simplify CI test plan routing
Collapse the nightly alternate plan into the shared event routing while preserving every GitHub output and schedule behavior. Strengthen the nightly characterization for all deterministic suites.\n\nAI assistance: prepared by OpenAI Codex under maintainer pbakaus's standing scheduled-refactor authorization.
2026-08-28 15:00:56 +05:00
Abdul WahabandClaude Opus 5 f379c4c76f COMP-FIDELITY: ninth sweep (sol, artifact fix confirmed) and tenth sweep (opus confirmation on the rebased branch)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 14:59:06 +05:00
github-actions[bot] 31dcc687c6 Sync generated provider output 2026-08-28 02:14:29 +00:00
45943c3b1f Fix: assert only the common ancestor of the glob roots as a URL prefix
Cursor's review caught the previous commit over-correcting. One tree listed
at two depths (prototype/*.html plus prototype/library/**/*.html) derived
two roots, and requiring a waiver to match under both stopped a normal
project-relative waiver like prototype/index.html from applying anywhere.

The rule both reviews were circling is simpler: one live session is served
by one server, so a single document root must sit at or above every
configured page. The only prefix the resolver can safely assert is the
deepest common ancestor of the glob roots. Nested roots collapse to their
shared tree, so normal waivers keep applying. Disjoint roots (src/ and
public/) share nothing, so no prefix is asserted and only the URL path
itself matches, which keeps the earlier fix intact: a src/foo.html waiver
still cannot hide a finding on a page served from public/foo.html.

This also deletes the match-under-every-root machinery from the previous
commit; with a single asserted prefix, plain matching is enough.

Also switches the new test file to derive the repo root from
import.meta.url rather than process.cwd(), per review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:13:43 +05:00
ce1c9f8dad Fix: a waiver scoped to one served root must not hide findings on another
Greptile's review found a real bug in the new resolver. When the live config
lists pages under more than one folder (src/**/*.html and public/**/*.html),
the overlay treated a URL like /foo.html as src/foo.html and public/foo.html
at the same time. A waiver written only for src/foo.html could then hide a
finding on the page actually served from public/foo.html. That fails in the
worst direction: a real finding disappears and nothing says so.

The overlay can never look up the right file. The live server does not serve
the pages; the project's own dev or static server does, and its URL-to-file
mapping is invisible from here. So the fix stops guessing: a file-scoped
waiver now applies only when it matches the URL path itself, which is true
whichever folder serves the page, or when it matches under every configured
folder, so no possible reading disagrees. Anything ambiguous shows the
finding, which is also what the CLI reports for the file really being served.

With a single configured root, the common case, nothing changes: the new
rule reduces to the old behaviour exactly. Multi-root projects keep three
ways to write a waiver that still applies: name the file under each folder,
use the bare path, or use **/.

Two new unit tests pin the ambiguous case and the safe spellings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:13:43 +05:00
5330fa358e Fix: honour .impeccable detector ignores in the live overlay (#639)
The live overlay's detect scan ran unfiltered: requestDetectScan() posted
only { scanId }, so detector.ignoreRules and detector.ignoreValues in
.impeccable/config.json reached impeccable detect and the edit hook but
never the surface a designer actually watches.

The server now serializes the project's detector waivers into the /live.js
prelude (window.__IMPECCABLE_PROJECT_IGNORES__), read per request through
hook-lib's readConfig so config.local.json wins and edits land on the next
tab reload. A new script part, live-browser-ignores.js, resolves that
config against the page URL when a scan starts: ignoreRules suppress
outright, wildcard ignoreValues suppress their rule in the files their
globs name, and the remaining entries ride along as disabledValues for the
detector to match on each finding's own value. The detector bundle applies
those where the findings are assembled, since the overlay draws its own
markers from the collected findings.

Scope resolution mirrors cli/lib/impeccable-config.mjs deliberately: the
same glob dialect (globToRegex, including {a,b} alternation), the same
path-suffix matching as findingMatchesScopedIgnoreFile, and the same
refusal to apply an unscoped wildcard entry. The served-root prefixes that
bridge project-relative globs and site-relative URLs come from the inject
config's own files globs, never from the ignore globs; deriving them from
the ignore globs lets one entry scoped to prototype/library/** lend its
prefix to every page and suppress site-wide, which looks like success
because the numbers go down.

Known gaps, recorded in the detector comment: the motion value extractor
is not mirrored, so a value-scoped bounce-easing waiver only matches when
the finding carries ignoreValue directly, and design-system-color matches
on the normalized string without the CLI's color-equality fallback.

Tests: unit tests for the resolver part (stale globals, string ignoreRules,
malformed entries, directory URLs, percent-escapes, glob metacharacters,
the roots trap), an extension-mode puppeteer test that disabledValues
suppress exactly the waived findings, and the live-browser regression pin
now asserts the new scan config shape instead of { scanId }.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:13:43 +05:00
Paul BakausandAbdul Wahab ae42c0c3ce COMP-FIDELITY: eighth sweep (opus 84/84 on 05, 79/78 on 07 with the scaffold and the SVG ban)
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 2896e28613 Hero code scans read index.html when start recorded no artifact; painted-note regex learns 'geometry', 'leader lines', 'thumbnail'
A sol build named its two carburetor drawings 'countable ... geometry' chrome regions, drew them in inline SVG, and the SVG ban never ran because state.artifact was null.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 1117672934 docs: the 2026-08-17 human review of comp-fidelity builds (verdicts and pin notes)
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 9ca77151de Register tests/hero-checks.test.mjs and lib/hero-checks in the suite map
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab bef185360f build-phase.mjs scaffold: the measured layout as CSS custom properties and a reference page
A reference, not the page: --r-<id>-x/y/w/h in % of the comp (plus cap height, font-size, family, weight where measured) to bind to any markup, and hero-reference.html with every region at its box and every plate placed with object-fit: contain, as a check on positions. Attacks the most common execution failure of weaker builders (badly positioned, overflowing, pushed below the fold) without dictating structure to strong ones; overlapping boxes are overlapping boxes and the gate reads pixels regardless.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 2debb7078f Hero refuses inline SVG illustrations; finish cannot record ship over an open phase; the comp-led path names its model tier
From the human review's most repeated pin ('terrible svg instead of asset', on every model) and from sessions that wrote 'ship' with the hero open. Icons, arrows, chevrons, and runtime data charts stay code; diagrams, notation, and leader lines are plates.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 866bd94b7e COMP-FIDELITY: final human verdicts on sweeps 6-7
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 38170564c6 Plates gate refuses a comp crop shipped as a plate; text readings include letter-spacing
From the final review batch: 'bad asset crop (crops are never allowed)' twice, 'letter spacing way too wide'. A crop resampled to the region scores 99.8% structure against the raw region; a produced plate scores 30-60.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 9746567ea9 COMP-FIDELITY: seventh sweep and the review's two verdict boundaries
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 77acd73cd3 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).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 7cea970c6c comp-spec snaps text and control regions to the largest ink mass in their grid span
A session's own note said its hero sat at 67 because the 10x10 grid boxes straddled two elements each, and it was right: every downstream measurement (cap height, line count, structure) inherited the slop. Text and control regions now snap to the dominant connected ink inside the span (page-ground threshold, dilated cells, masses touching the span's sides lose to inside masses), keep the span on the record for coverage, and can opt out with snap: false.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 36e6864d56 Controls are held like text at the hero: a contradicted control vetoes, a far drift is named; the icon concession covers glyphs only
Per pbakaus: close-enough icons are fine, arrows and dropdown chrome are not.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 693953806c COMP-FIDELITY: the human review, its calibration, and what each pin became
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab f80846ad85 Side-by-side shows the capture, not the shift-padded copy; colour reading on unmeasurable text; line pitch on 3+ lines
The shifted copy's padding read as a white 'letterbox' on the build in every human review. A vertical spine came back white on red where the comp had black in five builds; its ink colour is now compared even though its type cannot be measured.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 07e3fad3b6 Spec refuses a plate box that cuts its artwork; hero counts strong small invented inserts; painted-note regex no longer matches a label
From the second review batch: the best build of the fifth sweep passed the hero at 87% with the cover arch cut flat on the left (object-fit: cover on a box narrower than the shape), and legends, badges, and extra controls one or two cells wide slipped under the invented-ink floor. comp-spec measures the artwork's contiguous contact with each box edge against the page ground; the spec gate refuses such a box unless bleed is set. Human pass line landed at comp-diff 72-73; HERO_MIN stays 0.72.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 1931066107 COMP-FIDELITY: sixth sweep
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab bae0c24f45 Hero readings go advisory after three unchanged attempts; overall shows a decimal near the floor; a single link is not a strip
One cf6 session spent 27 attempts on the same three readings and read '72% < 72%'.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 9a1daacd76 Hero readings as an ordered edit list; a refused force points back at them
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 00a180380e Hero gate reads type, strips, and invented ink as numbers; every region needs a note; missing beats the text relaxation
From the first human review of sweep-3 builds (pins on 12 samples): fonts at the wrong size, weight, colour, or place; nav bars too tall; kickers and dividers the comp does not have; a footer strip pushed off the frame that read as drift on ground colour alone; a drawing filed as chrome with no note to catch it.

- lib/hero-checks.mjs: textRegionCheck (cap height, line count, ink density, ink colour, first-line offset vs the comp crop, measured fresh), chromeStripCheck (first rule row), inventedInk (build energy over a calm comp cell and neighbourhood). Wired into gateHero as reasons; invented ink vetoes at 4% of cells.
- comp-diff verdictFor: detailRaw < 0.15 is missing whatever the palette.
- comp-spec: every region carries a note.
- font-fingerprint: the tall-line filter takes its median over lines with real mass, so two display lines above a small line are not 'tall'.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab ba26730411 COMP-FIDELITY: opus arm and 07 re-pass
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 356362a410 comp-spec refuses a code region larger than a quarter of the comp
A session named seven regions for a page with three plates, a table, a note, callouts and a spine, so the hero gate could name nothing and the score sat at 70. A code region is one element; a column is a container of several.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab f5819fbd6a COMP-FIDELITY: fourth sweep
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 3e7e85daf7 font-fingerprint: full-height inked columns leave the row profile; forceAllowed needs the user's reported words and a downgrade
Staff rules and a black page edge fused eight track rows into one 389px 'line'. A session forced two gates by quoting a brief line ('should feel like an extension of her artwork') as permission; a force now needs the user's words reported or quoted, a downgrade verb, and the comp noun in one reason.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 2cc60a5348 font-fingerprint: measure the dominant lettering class in a mixed crop; NEXT prefers generate-image --plate
A comp region drawn on the 10x10 grid over-covers: a body-copy crop carries the last headline line above it and a drawing beside it, and one session measured 'thread-body' at cap 160px off a carburetor drawing and ranked Londrina Shadow for it. Tall non-text 'lines' leave the mass reference; lines cluster by cap height and the cluster holding the most ink (multi-line first) is measured, re-applied after upsampling.

The plates NEXT line now names generate-image.mjs --plate as the tool (harness image tool only as fallback) after a session spent 25 turns keying plates with magick.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 08ce88f565 Texture presence at the hero: structure over palette
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 4f2de6a0b6 Gates: a passed texture with held ground is placed; responsive does not re-score a passed plate as missing
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab caf9744763 Hero gate: a passed plate is placed material; plate rows travel on state; low-detail text with held structure is drift; wait long on plate generation
Also records the third sweep in COMP-FIDELITY.md (branch +7 to +18 points over main on three niches, sol).

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 99f73390db Comp fidelity: font ranking that holds without a browser, spec refuses painted chrome, control-box veto only for discrete controls
font-match / catalog index
- Index schema 2 adds a third render, 48c (48px cap, ALL CAPS text). Caps headline crops have no x-height band and ranked against mixed-case renders as barcode faces; they now route to the caps render.
- Non-text families (barcodes, redacted, flow, dingbats, effect faces) are excluded from candidates.
- The distance adds a gross width and weight gap (log ratio of advance and ink density) so a face 50% wider or 35% lighter cannot rank first on run-length detail alone; the index stores those readings.
- Multi-line all-caps crops vote on x-height across lines: one line's crossbars no longer give the crop a spurious x band.
- With no browser, --rank records the catalog's nearest face (source catalog, size estimated) so the spec gate can close; the NEXT line and new-work.md say not to install a browser or hand-write a choice.
- font-match stamps the choice it writes; the spec gate refuses a chosen face it did not write (sessions typed Arial Narrow into spec.json to pass).
- IMPECCABLE_NODE_MODULES lets a harness lend a playwright.

comp-spec
- A region note that describes painted material (diagram, drawing, photo, texture...) under a code kind is refused at the spec unless codeDrawn is set: the exploded carburetor filed as chrome is a plate about to be redrawn in SVG.

build-phase
- The control ink-box veto applies only when the comp's ink is a discrete element and the build's box is too; a full-width bar told one session six times that 1376x87 was 1382x102 with no edit able to move it.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 919c68d2b9 COMP-FIDELITY: record the second sweep (packets without state, prefix inertia, WebP comps)
AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
Paul BakausandAbdul Wahab 48350ffb14 Read WebP/JPEG comps through a sibling PNG cache instead of forcing PNG
comp-spec, comp-diff, build-phase, font-match, and generate-image now decode any comp raster via loadRaster(), converting non-PNG input to <file>.png next to the source. Sessions used to hit 'not a PNG' and rewrite the .webp in place with PNG bytes, which broke transcript replay (a later step rewrites the comp beyond the cut) and left a mislabeled file.

AI-assisted (Claude Code).
2026-08-28 06:13:59 +05:00
95294e464a font-match v2: fingerprint the comp lettering and pick candidates from a Google Fonts catalog index
lib/font-fingerprint.mjs replaces the three-number fingerprint with
size-invariant shape features (x-height ratio, stroke contrast, stem width,
run-length quantiles, roundness, serif signal, width spread) and a
noise-normalized distance; family recall on a held-out self-test rose from
13% to 72% top-5. data/font-index.json carries the whole Google Fonts
catalog (3,092 faces at two cap sizes, 707 KB); font-match --rank fingerprints
the comp crop, takes the 25 nearest faces from the index (plus the model's
own names), renders them at the comp's cap height, ranks by the same
distance, and prints a proof sheet and the CSS to use. scripts/build-font-
index.mjs rebuilds the index at release time.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
cacb2868ac No comps outside the state: generate-image refuses .impeccable/mocks/ output while a roll is pending and build-phase has not started
The first paid confirmation sweep showed the failure: models rendered the
three comps first and ran build-phase.mjs start after, so a session cut at
the composition pick carried no state.json and the resumed model followed
the conversation ('translate the comp into HTML now') instead of the
phases. Decision comps (.impeccable/mocks/decision/) are unaffected;
--force-mock overrides.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
62f59a3934 build-phase: gate errors are refusals that name themselves, never stack traces; fix ink-box crash on report shape
The first paid confirmation run hit a TypeError in the ink-box check
(report regions carry normalized w/h at the top level, not under box);
runGate now catches a throwing gate and returns a one-line refusal with
an explicit force path so the run is not lost to a tool bug.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
cbe89a1969 Round-4 sim fixes: lead text region by cap height, ink-box only for discrete controls, grain allowed where the comp is grainy, textures cannot block responsive alone
AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
f5751c4d75 font-match: choose the face by metrics; chroma-keyed plates; ink-box report; verbatim words in the hero
font-match.mjs fingerprints a text region's lettering in the comp (cap
height, glyph advance per cap = width class, ink fraction = weight class,
tracking), renders candidate faces at that cap height in a headless
browser (yours plus a shortlist for the width class), and ranks them by
distance with a proof sheet; the spec gate refuses to close until the lead
text region is measured and ranked. generate-image --plate keys ink-on-
ground plates to alpha (chroma) so the drawing sits on the page's own
ground; the plates gate scores keyed plates composited over the region's
ground. comp-diff reports each region's ink box; the hero gate names a
control whose box height or width differs from the comp. The hero
instruction copies the comp's words verbatim; rewording is a stated
decision after the hero passes.

Driven by a human review of the r3 side-by-sides: face width and weight,
plate ground, control row height, and content substitution.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
b015e26ddf Round-3 sim fixes: record hero is not an attempt; texture bands under present ink are drift; capture guidance
AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
f704fca29c forceAllowed: a 'truthful translation' the model proposed is not the user downgrading the comp
AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
bfa6014796 Round-2 sim fixes: one plate rule, plate size from the gate's floor, missing means empty
plateVerdict() is shared by the plates gate and generate-image's PLATE-WARN
so they cannot disagree; --plate picks a frame that clears the 1.5x width
floor (a square region wider than 682px takes the 1536 landscape frame);
'missing' on text/chrome/control regions requires the build region to be
near-empty, so a 12px rule a few pixels off reads as contradicted or drift,
not missing; the responsive gate does not re-litigate a plate that passed
the hero; record hero after close does not inflate the attempt count.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
af4ac68805 Plates: textures tile a clean comp patch first; record hero reports plate rows
AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
e618357a69 Responsive gate: the desktop capture must still read as the comp
Round-1 simulated builds passed the hero at 1536 and shipped a page whose
first viewport collapsed to one column at 1440 (comp-diff 50% on the
final capture, 82% on the hero). The responsive phase now requires
desktop.png and mobile.png and diffs desktop.png against the comp at 65%
with no region missing.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
24773eeedf Hero gate: text and chrome regions read as drift once structure and palette hold; scripts run through symlinks
Three simulated builds under the previous gate reached 78-83% overall with
the exploded plate placed and the table right, then spent 12-20 attempts
chasing 'contradicted' verdicts on a headline set in a substitute face and
on 50px chrome strips whose detail was paper grain. Text with structure
above the floor and its palette intact is drift; chrome and controls with
structure and palette held are drift. The adversarial set (swapped
columns, mirror, sepia, noise plate, tile shuffle) still fails.

isMain uses realpath on both sides so a skill mounted through a symlink
(Cursor, worktrees, staged evals) still runs its CLIs.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00