Commit Graph
518 Commits
Author SHA1 Message Date
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
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
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
d9a155be8c Gates that cannot be talked past: metric hardening, one start command, uncovered-ink refusal
From a forensics pass over twelve runs and two adversarial passes over
the metrics:

- comp-diff: detail is signed and penalizes invented energy; regions with
  structure under 0.3 (or painted regions under 0.45 / added detail over
  0.4) are contradicted whatever the mean says; palette ramp tightened;
  region crops inherit the whole-image best translation so a shifted page
  is not eight contradicted regions.
- hero gate: fails on any contradicted plate/image/text region (chrome and
  controls keep the one-third allowance), on a capture that is not the
  comp's frame, on a palette that is not the comp's, and on an organic
  clip-path drawn inside a raster region's box.
- plates gate: scored against the comp crop with overlapping text/chrome
  painted out (comp-spec plateReference; generate-image uses it too), with
  a structure floor and an added-detail veto; the real plate passes, noise,
  mirrors, mosaics, and other regions do not.
- comp-spec refuses a regions file that leaves comp ink unnamed.
- The direction-choice ping is folded into build-phase.mjs start
  --direction --kind; the roll writes .impeccable/build/pending.json and
  context.mjs / detect.mjs report COMP_ROUND_OPEN until the hero gate
  passes. A code-led config makes start print the contract step and stop.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
e0ec77b4bb Lock down the scroll-clip case for text-occlusion (#602)
The paintedRect clamp landed in 9d2b0556 without a fixture, so nothing
stopped the false positive coming back. This adds the shape that produced
it: a scroll region with an opaque bar directly beneath.

Text scrolled past the panel's bottom edge still reports its full
unclipped rect, and that rect lands on the bar. The probe then samples
coordinates the text is not painted at, finds the bar, and reports the
text as buried under it. Any sticky footer or toolbar under a scroller
has this shape.

Verified red then green: with the clamp reverted to main's version the
fixture reports a fourth finding and the assertion fails; with it in
place the count holds at three.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
6dd15238c4 Close the comp-round gap and make the hero gate teach
concept-seed's choice ping now prints the next mandatory step from the
recorded build path (comp-led: build-phase.mjs start --direction <key>),
because every run that skipped the comp round did so right after that
ping. build-phase gains a comps phase ahead of spec (three sidecar'd comps
under .impeccable/mocks/, one approved) and records the approved comp on
close. The hero gate lists the worst region crops first with the fix class
per verdict, and refuses a third value-only attempt on the same stuck
region. Hero instruction is plates first, then the semantic layer. The
finish reviewer treats a comp-led build with no closed comps phase as a
material finding.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:59 +05:00
f4987eebba Hero gate refuses while a produced plate is unreferenced by the source
The first live run produced a faithful carburetor plate, then drew the
region in SVG and left the plate on disk. Before diffing, the hero gate
now walks the artifact (or a bounded source tree) for every plate's file
name or a data URI named for it.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:27 +05:00
63dd7faa0e build-phase: textures skip the size floor, --force needs the user's words
The first live run forced past the plates gate with 'single-file HTML
delivery requires embedded CSS/SVG'. That is not a reason the comp's
authority moves for; the script now refuses a --force whose reason does
not quote the user, and new-work.md says a single-file deliverable inlines
the plate as a data URI. Texture plates are judged on palette and grain,
not size or structure, since they tile.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:13:27 +05:00
5856161014 Plate pipeline, asset producer rewrite, and two detector rules for CSS standing in for material
generate-image.mjs --plate produces one raster region of the measured spec
from the comp crop, scores it against the crop, and refuses under --min.
The asset producer's job becomes producing the spec's plates. Detector
gains organic-clip-path (many-vertex polygon / curved path() clips) and
buried-raster (raster under a near-opaque wash or at near-zero opacity),
wired into both engines with fixtures.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:09:46 +05:00
b0fc2e8801 Add comp-diff, comp-spec, and build-phase: measured comp fidelity for the build phase
Dependency-free PNG codec, perceptual metrics (structure / color / detail /
bands), side-by-side + heatmap + per-region crops, a measured spec from the
approved comp (grid overlay, sampled palette, plate list), and a phase state
machine whose spec / plates / hero gates run the diff instead of asking the
model to remember the image.

AI-assisted (Claude).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 06:09:46 +05:00
377fb112b0 Pass the session key from detached idle-grace tests
Main's #469 tests POSTed /heartbeat and /answer without ?key=, which the
gate now rejects, so those daemons looked dead. The e2e heartbeat counter
also has to match pathname rather than a suffix, now that the URL carries
the key.

Written with AI assistance under maintainer direction.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:25 +05:00
7982002dac Allow bare loopback Host/Origin on port 80, where browsers omit the suffix
Bugbot caught that the exact-match allowlists 403 every request on --port 80
because browsers drop the default-port suffix; other ports stay strict.

Written with AI assistance under maintainer direction.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:25 +05:00
2e075dc58c Gate the build-path flip behind the same session key and origin checks
An unauthenticated POST /build-path wrote the flip event that makes --wait
instruct the agent to generate comps: same class as the /answer hole in #555.

Written with AI assistance under maintainer direction.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:25 +05:00
eaaecbd1fe Fix: require session key and origin/host checks on serve-question POSTs (#555)
Unauthenticated POST /answer copied steer into the agent ANSWER line. The handler now requires the detached session key and rejects foreign Origin and Host.

Written with AI assistance under maintainer direction.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:25 +05:00
d690349db1 Fix: keep URL basic-auth credentials on the scan origin (#657)
page.authenticate is page-wide, so a cross-origin redirect that then 401s would receive the original credentials. Attach Authorization only to requests for the scan origin.

Written with AI assistance (Cursor); reviewed by maintainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:01 +05:00
d5873ff8eb Fix: redact URL userinfo from detect findings (#657)
Strip basic-auth credentials from scan-target URLs before goto and finding output, and pass them to page.authenticate instead.

Written with AI assistance (Cursor); reviewed by maintainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:53:01 +05:00
be87f5eb86 Fix: refuse inert exact ignore-value entries (#662)
ignore-value stored exact values for rules that cannot extract one, so the entries never matched. Refuse them and point at "*" --file.

AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:43:36 +05:00
5d932f9fbe Fix: safe temp staging and downloadFile error handling (#479)
AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 05:43:04 +05:00
Abdul WahabandCursor daae1d4117 Fix: reject root-relative .. segments and warn per scan
Dot-segment hrefs like /../outside.css could leave the project, and a process-wide warning set hid missing-sheet notices on later detectHtml calls.

AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 19:47:54 +05:00
Abdul WahabandCursor 2b88aa5231 Fix: resolve root-relative linked stylesheets in static detect (#652)
Root-relative hrefs like /static/app.css were treated as OS-absolute and silently dropped, hiding contrast findings.

AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 19:34:55 +05:00
Abdul WahabandGitHub 356b761391 Merge pull request #594 from pbakaus/fix/570-monorepo-design-root
Fix: inherit the monorepo root's DESIGN.md in detect design-system rules (#570)
2026-08-25 17:16:47 +05:00
Abdul WahabandCursor 47e411952b Fix: own nested workspace packages and honor projectRoots first (#570)
packages/* now includes nested package.json dirs under a matched
workspace package, and Impeccable projectRoots govern a path even when
package-manager workspaces exclude it.

Written with AI assistance (Cursor); reviewed by maintainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 08:03:16 +05:00
Abdul WahabandCursor 6bea544a0a Fix: drain context stdout before process.exit (#573)
process.exit after a queued write truncated boot output on a backpressured pipe. Await the write callback, then close the fetch dispatcher.

AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 07:51:47 +05:00
Abdul WahabandCursor 5d7c1cce34 Fix: inherit DESIGN.md only from a monorepo root that owns the path (#570)
findDesignRoot continued past every workspace package.json to any
workspace-declaring ancestor. It now matches the boundary against that
ancestor's globs (including negations and globstars), so excluded and
stray packages do not inherit, while included workspaces still do.

Written with AI assistance (Cursor); reviewed by maintainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 07:47:16 +05:00
Abdul WahabandCursor 2ef8e43d1e Fix: close fetch sockets before context helper exit (#573)
On Windows/Node 24, a live undici keep-alive from the update-check fetch aborted libuv during teardown after valid stdout. Destroy the dispatcher first, matching concept-seed.

AI assistance: implemented with Cursor Grok 4.6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 07:31:18 +05:00
Abdul Wahab 043e8a5bfd Merge origin/main into fix/570-monorepo-design-root 2026-08-25 06:58:14 +05:00
Abdul WahabandCursor 2064b0696f Merge origin/main into fix/603-codex-stop-payload
Keep Codex as its own Stop harness (decision/block) while taking main's Grok envelope detection and Stop cache sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 07:25:47 +05:00
Abdul WahabandGitHub f849d610f3 Merge pull request #648 from pbakaus/fix/646-grok-hook-stdin
Fix: parse Grok Build camelCase hook stdin (#646)
2026-08-24 07:18:24 +05:00
Abdul WahabandClaude Fable 5 bfe634e254 Trim the Grok normalizer to the fields the hook reads
The hook_event_name mapping (and its pre_tool_use entry) had no reader:
hook.mjs routes on the raw stdin via isStopEvent, and nothing downstream
keys on the normalized event name. The trailing-slash strip duplicated
the path.resolve every consumer already does. Pin the one commit-2
behavior that had no test: a Stop detector failure must leave the
remembered set alone.

Prepared with AI assistance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 06:52:52 +05:00
Abdul WahabandCursor 3c442af7ad Fix: sync Stop finding cache after a clean Grok scan
A clean Stop never replaced remembered keys, so a finding that was fixed and then reintroduced stayed silent. Remember the live scan, including empty, and persist that write.

Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 06:23:45 +05:00
Abdul WahabandGitHub c0b1ec6fef Merge pull request #644 from pbakaus/fix/642-grok-global-hook
Fix: rewrite Grok project hooks to the global skill path (#642)
2026-08-24 06:14:38 +05:00
Abdul WahabandCursor 35ae07339b Fix: parse Grok Build camelCase hook stdin (#646)
Grok was classified as GitHub Copilot, so the design hook skipped every
edit with no-file-path and never ran Stop. Normalize toolInput/sessionId
and treat Stop additionalContext as the Grok product.

Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 05:28:21 +05:00
Abdul WahabandCursor c9e7cd8a64 Fix: emit Codex Stop hook as decision/block (#603)
Codex Stop rejects Claude's hookSpecificOutput shape. Detect Codex from
turn_id at runtime and emit { decision: "block", reason } so existing
installs keep working without rewriting hook commands.

AI-assisted change, prepared with Cursor Grok under maintainer direction.

Fixes #603
Fixes #643

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 05:23:51 +05:00
Abdul WahabandGitHub 2c39c39f16 Merge pull request #631 from pbakaus/fix/488-strip-reserved-poll-fields
Fix: strip page-controlled poller fields before they reach the agent (#488)
2026-08-24 04:32:49 +05:00
Abdul WahabandGitHub 82cb738f46 Merge pull request #629 from pbakaus/fix/618-live-source-symlink
Fix: stop live-server /source from following symlinks out of the workspace (#618)
2026-08-24 04:29:43 +05:00
Abdul WahabandCursor 49571365a8 Fix: rewrite Grok project hooks to the global skill path (#642)
Grok was skipped by the hook-command rewrite, so a global skill install left .grok/hooks/impeccable.json pointing at a project-relative hook.mjs that does not exist.

AI assistance: Cursor Grok 4.6 implemented this change.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 04:27:01 +05:00
Abdul WahabandGitHub a735bc55cd Merge pull request #630 from pbakaus/fix/592-oklch-parseanycolor
Fix: parse oklch in visual-contrast and neon-text (#592)
2026-08-24 04:26:19 +05:00
Abdul WahabandGitHub 2e8f8dfdae Merge pull request #632 from pbakaus/fix/589-comment-strip-markup-css
Fix: strip comments in markup and stylesheets before regex matchers (#589)
2026-08-24 04:23:05 +05:00
Abdul WahabandGitHub 26bb3d3af5 Merge pull request #635 from pbakaus/fix/615-grid-1d-rails
Fix: stop flagging 1D dashed rules as grid backgrounds (#615)
2026-08-24 04:17:50 +05:00
Abdul WahabandGitHub 1a7ee36324 Merge pull request #634 from pbakaus/fix/578-color-mix-nested-hex
Fix: skip hex nested in color-mix when measuring gradient contrast (#578)
2026-08-24 04:10:43 +05:00
Paul Bakaus 809976638d Share doctor boot finding policy
Centralize the shared boot artifact checks so doctor adds only its deep checks while preserving the existing finding order and CLI contracts.

AI-assisted: prepared by Codex under maintainer pbakaus scheduled-refactor authorization.
2026-08-22 11:58:26 -07:00
Abdul WahabandCursor 9a7d0fbc50 Fix: skip regex literals in Astro fences and url() protocol-relative slashes
Quote-bearing regexes made the frontmatter closer miss the closing ---, and url(//…) plus interpolations were treated as SCSS line comments that hid live font-family. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 07:13:18 +05:00
Abdul WahabandCursor ba873f7599 Fix: blank preprocessor line comments inside component style blocks
Standalone SCSS/Sass/Less files already ignored // comments, but <style lang="scss"> in Astro/Vue/Svelte still scanned them as live CSS. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 07:02:44 +05:00
Abdul WahabandCursor 7ddcd533a4 Test: pin 1D grid-background pass cases in the fixture suite
The unit suite already covered dashed rules; this adds an isolated HTML fixture so the page-level one-finding cap cannot hide a regression.

Prepared with AI assistance (Cursor agent), directed by @abdulwahabone.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:58:36 +05:00
Abdul WahabandCursor 7426af446e Fix: give the color-mix hex fixture explicit pixel size
jsdom does no layout; Greptile asked for width/height on .mix-hex-brand so the static fixture stays deterministic. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:54:26 +05:00
Abdul WahabandCursor a236137bc6 Fix: stop flagging 1D dashed rules as grid backgrounds (#615)
codex-grid-background treated any 2D px background-size as a grid, so a single hairline tiled as a dash or rail false-positived. A finding now requires two hairline gradients plus a px tile.

Prepared with AI assistance (Cursor agent), directed by @abdulwahabone.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:51:25 +05:00
Abdul WahabandCursor ddb609936a Fix: keep comment blanking out of script strings, preprocessor //, and Astro fences
Naive HTML/CSS comment regexes were swallowing live markup between script-string delimiters, SCSS/Sass/Less line comments still reached the matchers, and indexOf treated --- inside a frontmatter template literal as the closing fence. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:49:20 +05:00