mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-17 08:36:25 +03:00
baa76cfd05d343202dd0dc1fc74dc0dcd89ee0a2
46
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c90faaab55 |
Simplify import graph scanning
Replace three duplicate matcher loops with one declarative pattern list while preserving import resolution behavior. Add Sass @use and @forward characterization coverage.\n\nAI-assisted change prepared under pbakaus's scheduled architecture-refactor authorization. |
||
|
|
872c032582 |
Ignore rounded-none in border accents
AI-assisted change. |
||
|
|
8ebcfccc64 |
Scope the page-level pattern checks to style carriers, not raw source
The static engine's checkHtmlPatterns ran its CSS-property regexes over the entire source string, so documentation ABOUT css flagged as css: impeccable.style's changelog line naming background-clip: text inside a <code> tag tripped gradient-text, the purple hexes in a <pre> sample read as the AI palette, and a commented-out stripe rule counted as a live one. The browser path shared the exposure through outerHTML. The fix is engine-level, not a per-rule patch. The pattern pass now scans scoped corpora: styleText carries <style> block contents, style="" attribute values, and the linked stylesheets the static engine already reads for the cascade; classText carries class attribute values for the utility-class scans. The static engine builds both from its parsed document, so escaped code samples never contribute; other callers fall back to a tag-scoped extraction in buildHtmlPatternCorpora, and bare CSS input stays its own style text so direct callers keep working. The pulsing-dot and marquee scanners take a second markup argument for the parts that really are markup: landmark ranges, Tailwind class positions, the <marquee> tag itself. Rendered-text checks (theater phrases) and markup-shaped checks (svg scenes, img hover classes) keep the full source on purpose. No registry ids change; this is scoping, not a new rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
aeacf55074 |
Add .vuepress to the hidden source-dir allowlist
Cursor Bugbot correctly noted classic VuePress keeps theme layouts, components, and styles under .vuepress/, which the walker scanned before the hidden-dir rule. Same treatment as .vitepress and .storybook. Prepared with AI assistance (Claude Code), directed by @pbakaus. Co-Authored-By: Claude Code <noreply@anthropic.com> |
||
|
|
a1a6441ba1 |
Exempt hidden dirs that conventionally hold UI source from the skip rule
Greptile's review correctly flagged a regression in the blanket hidden-dir skip: .vitepress/theme/*.vue and .storybook/ preview files are real UI source that the walker scanned before this branch. Both the walker and the scan-target filter now carry a two-entry allowlist (HIDDEN_SOURCE_DIRS) for those conventional locations; every other hidden dir keeps being skipped. Prepared with AI assistance (Claude Code), directed by @pbakaus. Co-Authored-By: Claude Code <noreply@anthropic.com> |
||
|
|
9f008ebf82 |
Skip hidden dirs in the detector walker and vendored paths in scan targets
When impeccable (or any agent tool) is installed into a project's .claude/.cursor/.codex tree, a root scan descended into the vendored skill code and reported the detector's own example strings as findings, and context-signals returned installed-skill files as scan candidates whenever the harness tree appeared in the branch diff (issue #303). Rather than growing SKIP_DIRS by a denylist of harness names that drifts as new tools appear, the walker now skips every hidden directory during recursion — which already covered .git/.next/.nuxt/.svelte-kit/.turbo/ .vercel, and covers all present and future harness installs plus .impeccable itself. SKIP_DIRS shrinks to the four non-hidden entries. An explicitly passed hidden target still scans: only child entries are name-checked, never the root the walker is given. scanTargets() applies the same rule to git-changed files (directory segments only, so root dotfiles keep their existing behavior), and falls through to source-dir targeting when the only dirty files are vendored. Prepared with AI assistance (Claude Code), directed by @pbakaus. Co-Authored-By: Claude Code <noreply@anthropic.com> |
||
|
|
144cee5c36 |
Fix detector coverage for generated UI tells
Remove provider gating, share grid-background detection across source and rendered scan paths, and update the detector catalog and tests.\n\nAI-assisted: prepared by Codex at Paul's request. |
||
|
|
77c7d8e0fc | Refine product and visual work lifecycle | ||
|
|
bbed6eef08 |
Refresh the Impeccable product experience
Rework the landing page proof, steering demo, feature grid, slop catalog, detector coverage, theming, Live workflow, and responsive behavior.\n\nAI-assisted implementation by OpenAI Codex. |
||
|
|
8682c85c57 |
Fix Live side-tab validation gaps
Scan Astro style blocks for inset-shadow stripes, recognize semantically chromatic external tokens without flagging neutral unknowns, and make the polling generator run advisory detector checks before publication. Sync the affected detector bundles and add a paired regression fixture.\n\nAI-assisted: Codex analyzed the failed Live task, implemented the detector and generator changes, and ran the validation suites under maintainer direction. |
||
|
|
dc0b25d393 |
detector: hero pulsing-dot promotion, nav-CTA contrast gap closure, shape-assembled-illustration (56 -> 57)
Item 1 (hero liveness theater):
- pulsing-dot now merges declarations per selector across rule blocks
(cascade-approximate), descends into media queries, and strips
prefers-reduced-motion: reduce overrides before the predicate runs.
Catches the shipped split-block constructions (size in the base rule,
animation added later or inside a no-preference media block).
- Dots whose element sits inside a header/nav landmark are promoted to
error severity (string-level landmark ranges in both engines); the
browser engine additionally promotes dots resting in the first ~900px.
- blinking-cursor findings in the first ~900px or inside header/nav are
promoted from advisory to warning.
- Per-finding severity overrides now flow through static-html,
browser-injected serialization, and detect-url.
Item 2 (nav-CTA contrast constructions):
- The a24-opus 01/002 header CTA already fires (specificity cascade +
oklch + var() all resolved); systematic sweep found two remaining
escapes and closes both:
- own gradient background on a SAFE_TAGS element (checkColors styled-
control exception now treats an own gradient as an own surface,
contrast measured against the worst stop)
- ::before/::after full-cover surface (static cascade marks pseudo
surfaces; browser adapter reads the pseudo computed style) so text is
measured against the surface the browser actually paints
- nav-cta-constructions fixture locks all eight computable construction
families; background-image: url() remains unflaggable by design.
Item 3 (shape-assembled-illustration, slop/advisory):
- New rule for large inline SVGs composing a pictorial scene from >= 8
primitive shapes at >= 200x200 intrinsic size with >= 3 distinct fills.
Charts (axis labels), stroke-only technical drawings, icons/logos
(small explicit size), and pattern-tiled backgrounds are exempt.
1.8 percent fire rate over the 3069-sample eval corpus, all verified
pictorial scenes; zero fires across val-a22/val-a24.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
7a99e1725d |
detector: four human-review rules — nav-CTA oklch contrast, numbered section labels, floating side-tab stripes, repeated card text
Four gaps found shipping in Opus 4.8 eval samples during human review: 1. low-contrast (extended): the browser adapters parsed text/own-bg colors with parseRgb only, so Chrome's oklch()-serialized computed colors silently skipped every contrast check — a flat dark-on-dark nav CTA (broader nav selector beating the button class) shipped at 1.5:1 undetected. checkElementColorsDOM and readOwnBackgroundColor now fall back to parseAnyColor. Near-threshold ratios print two decimals so a 4.497 finding no longer reads "4.5 needs 4.5". 2. NEW numbered-section-labels (slop, advisory): tiny (<=13px) styled numeric index labels riding beside section headings, repeated across 2+ sections with distinct indices. Sibling of repeated-section-kickers (which deliberately excludes bare numeric labels); handles both the direct prev-sibling shape and label-before-heading-wrapper shape. List/nav/table/card-item numbering is exempt. 3. side-tab (extended): the vertical pseudo-element stripe scan required the stripe to touch both corners (top/bottom 0 or height 100%), so a left accent bar inset a few px from each end evaded it; small end insets (<=20px each) now count. Added a browser-side pseudo-element check (getComputedStyle(el, '::before'/'::after')) since runtime- assigned custom-property colors are invisible to the text scanner. Selection-state exemptions stay as narrowed: only aria-selected=true / aria-current / active-class markers exempt, plus button/link affordances on the horizontal variant. 4. NEW repeated-container-text (quality): the same literal string (>=4 chars, contains letters) rendered 3+ times at 3+ structurally distinct positions inside one bordered/elevated container. Parallel/templated repetition (table cells, calendar grids, nav lists, identical sibling rows) never counts — structural signatures, not word lists. Verified: each rule fires on its repro sample via the file:// browser scan; clean eval samples add no new findings (the new low-contrast hits on other samples are genuine sub-AA oklch button pairs). Full test suite green; browser bundle regenerated; README/homepage rule counts bumped 49 -> 51 (docs-integrity test enforces them). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b6304913ef |
detector: narrow the tab-strip stripe exemption to actual selection state
Tab-strip MEMBERSHIP no longer exempts chromatic top/bottom stripes — only a real selection marker does: aria-selected="true", aria-current (any non-false value), or an active/current/selected class hint. A stripe repeated on every tab in the group ([role=tab], .tabs items, aria-selected="false" tabs) is decoration and flags as side-tab; the selected tab's own underline — including the reserved-space transparent-border pattern — stays legal. Applied consistently across the element border path (isTabContextElement), the pseudo-element stripe scan, and the inset box-shadow stripe scan. Also replaces a stray NUL byte in the marquee scanner's dedupe key that made tools treat checks.mjs as binary. Browser bundle regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ea44f514f9 |
detector: grid-background variants, dash-prefix eyebrow, marquee rule, inset-shadow stripes
Four gaps from human review of gpt-5.6 eval artifacts: 1. codex-grid-background variants: the block scan now also matches the inverted end-of-tile hairline form (transparent calc(100% - Npx)) and reads the tile cell from the background shorthand's `/ Npx Npx` slot, not just background-size declarations. A single hairline layer qualifies when tiled by a px pair cell (page-scale line field); percent-tiled single hairlines (background-size: 25% 100% rules on data-viz tracks/graphs) stay legal. 2. hero-eyebrow-chip branch C (dash-prefix): sentence-case, regular- weight microlabels above the h1 announced by a short chromatic ::before/::after bar (8-80px x 1-6px, accent fill). Static cascade marks dash-pseudo targets during rule collection; the browser path reads getComputedStyle(el, '::before'/'::after'). 3. New `marquee` slop rule: <marquee> elements, and infinite animations bound to keyframes with >= 20 percentage points of X travel. Percent travel only — px-travel loops are bespoke product animations (waveform playheads, progress sweeps). Centered elements animating other properties (constant -50% X), non-infinite slide-ins, rotations, and pulses never qualify. 4. side-tab inset box-shadow variant: single-edge inset shadows (3-12px offset on one axis, no blur/spread, chromatic) drawn as stripes on cards/badges/menu items. Selection-state indicators ([aria-current], [aria-selected], [role=tab], active/current/selected hints, interaction states) stay exempt; the same stripe repeated unconditionally on every item flags. Narrow fixed-width glyphs (logo marks) are exempt. isTabContextElement narrowed to match: bare nav ancestry no longer blanket-exempts top/bottom border stripes — only explicit tab semantics or state markers do. Browser bundle regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1a4b5c2fa2 |
detector: hover-state contrast + color-mix/compositing, radial-halo rule, top/bottom stripe variant, file:// browser scans
Four changes driven by human design review of eval artifacts:
1. Static engine contrast fidelity (nav-CTA cascade miss):
- parseAnyColor evaluates color-mix() (premultiplied sRGB mix; exact
for the dominant `color-mix(in oklab, C n%, transparent)` chip form)
- extractStaticColor captures color-mix() balanced instead of plucking
"transparent" out of the expression
- resolveBackground composites translucent layers over the opaque base
in both engines instead of skipping (static) or returning them
as-if-opaque (browser)
- NEW hover pass in the static cascade: :hover rules are matched via
state-stripped selectors, merged per-property against the resting
cascade with real specificity, and checked for WCAG contrast on
styled controls (checkHoverContrast). Catches the recurring miss
where a broader selector (.nav-links a:hover) beats the CTA's own
hover color and drops the pair below AA.
2. New `radial-halo` slop rule: chromatic radial-gradient wash (visible
saturated center -> transparent) as a decorative background on a dark
page. Exempts achromatic vignettes, opaque-end sheens, px-stop dot
textures, url() photo layers, and translucent (<0.7 alpha) staged-
light washes. Separate id from dark-glow so dashboards track the
gradient-drawn variant independently.
3. side-tab horizontal variant: 3-12px chromatic border-top/bottom (and
top/bottom-anchored full-width pseudo stripes) on cards/badges flag as
side-tab. Exempt: tablist/nav/aria-selected underlines, link/button
affordances, table cells, hr, state-conditional pseudo stripes, and
>12px bands. Badge-shaped spans (own visible background) participate.
4. CLI: file:// URLs route to the Puppeteer browser engine (~2s on a
50KB page), and detect --json findings now carry the registry
`category` field so downstream QA loops can separate mechanical slop
tells from judgment calls.
Fixture policy update: flat 3px top-accent cards moved from should-pass
to flag columns; tablist-underline and 16px-band pass cases added.
Browser bundle regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
cfdb7d4c81 |
detector: catch pseudo-element side stripes; add pulsing-dot rule
Two gaps surfaced by human eval review of real artifacts: 1. side-tab missed the pseudo-element variant. The accent stripe drawn as an absolutely-positioned ::before/::after (left/right: 0, top+bottom: 0 or height: 100%, narrow width, colored background) uses no border property at all, so neither the element-level border checks (pseudo elements never enter the static cascade or DOM walk) nor the border-left/right regexes could see it. New scanCssTextForPseudoStripe scans stylesheet text for that shape, mirroring the border rule's gates: >= 3px thick (<= 12px), chromatic fill (var()-resolved, neutral dividers skipped), full height against a side edge, with the blockquote/prose exemptions preserved. 2. New pulsing-dot rule (slop): small circular "live" indicator dots (<= 16px, border-radius >= 40% or pill values) bound to an infinite animation whose keyframes vary opacity, scale, or box-shadow — or pulse/blink/ping names when the keyframes aren't in the scanned text — plus the Tailwind animate-ping/pulse + rounded-full + tiny-size utility combo. Rotation-only keyframes (spinners) never flag, including when they hide behind a pulse-like name. Both scanners live in checkHtmlPatterns, so the static-html engine and the browser bundle share the same detection path. Browser/extension bundles regenerated; docs rule count bumped to 47. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0d72991bc8 |
detector: catch glow shadows in any color format, zero-offset halos on any background, and text-shadow glows
- parseAnyColor now covers oklab(), hsl()/hsla(), hwb(), and ~35 common named colors on top of rgb/rgba/hex/oklch, so checkGlow sees the color regardless of authoring format (Chrome preserves oklch() in computed styles, which the old rgba-only match silently passed). - checkGlow gains a second tell: a zero-offset chromatic box/text-shadow with blur > 4px is flagged on ANY background (the halo pattern); achromatic zero-offset shadows and focus rings stay legal. The existing chromatic-blur-on-dark-background rule is unchanged in semantics but now parses every color format. - text-shadow is checked wherever box-shadow was (browser DOM path with inherited-value dedupe, static engine via new textShadow cascade support, text engines). - The page-level text scan (regex engine + checkHtmlPatterns) is now a shared scanCssTextForGlow that resolves single-level var() refs against custom properties collected from the same text; unresolvable var() in a shadow color position is skipped, never guessed. Its dark-page heuristic accepts var()/oklch backgrounds but only when declared at root scope (body/html/:root or body inline style). - dark-glow keeps its id; registry name/description updated to cover both cases. Validated: three eval repro samples with oklch / var(--x) glows that previously produced zero findings now flag on the static CLI path; ten known-good largerun samples stay clean except one with genuine amber status-dot halos (0 0 12px oklch(.73 .17 65/.4)). Note: cli/engine/detect-antipatterns-browser.js and the extension detector are generated and still need 'node scripts/build-browser-detector.js' + 'node scripts/build-extension.js' once builds are unblocked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f40e2f8f0a |
Add mechanical pre-scan for typeset and layout (#345)
* Add mechanical pre-scan for typeset and layout commands. Introduce --scope filtering, layout/type rule scopes, DESIGN.md font-size validation, and pre-scan steps in the skill references so agents run detect before LLM judgment. Fixes #149 Co-authored-by: Cursor <cursoragent@cursor.com> * Add isolated sub-agent orchestration for typeset and layout pre-scans. Run the mechanical detector and visual assessment in parallel sub-agents so deterministic findings cannot anchor LLM judgment, matching the critique pattern Paul requested on PR #345. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: reject bare --scope so detect never scans unscoped by mistake. When --scope had no value, the CLI dropped the flag and ran a full scan instead of failing, which could silently use the wrong rule set during typeset/layout pre-scans. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: require both typeset and layout assessments in sub-agents. Close a loophole where agents ran only the mechanical pre-scan inline by interpreting "running both" as permitting one inline assessment. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Abdul Wahab <abdulwahab@Abduls-MacBook-Pro-2.local> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
9f49cb85cc | Fix Google Fonts css2 family parsing (#349) | ||
|
|
07667ed08f | Add quiet mode to detect CLI (#259) | ||
|
|
c7539c867d | Fix live picker sizing and divider detection | ||
|
|
51d01e3a5f |
[codex] Add design-aware detector rules (#252)
* Add design-aware detector rules * Fix design-aware detector noise * Unify CLI and hook detector ignores * Fix remaining design-system review findings * Add detector ignore CLI * Fix design detector review findings * Fix design color source false positives * Fix core test suite registration * Add design-aware detector docs * Fix font priority design-system parsing * Fix color ignore value matching |
||
|
|
858b9bbea6 | Improve hook false-positive handling | ||
|
|
9b0b63c04f | Prepare CLI 3.0.0, skill 3.6.0, extension 1.2.0 | ||
|
|
672517f76e |
Add automatic design hook install and exceptions (#170)
* docs: add PRD for design detector hook integration Plans a PostToolUse hook for Claude Code and Codex that runs the existing design detector after every relevant file write and feeds findings back to the agent as advisory system-reminder context. No implementation in this commit; covers UX, technical design, build pipeline changes, distribution, coverage tradeoffs, and rollout. Co-authored-by: Cursor <cursoragent@cursor.com> * docs: revise hook PRD with best-practices review Folds in the P0/P1/P2 findings from an online best-practices critique against the official Claude Code and Codex hook references plus 10+ 2026 community guides and similar prior-art tools (claw-hooks, claude-code-hooks-mastery). Key changes: - Exec form everywhere (Codex snippet was shell form), with Windows rationale. - Default timeout dropped from 10s to 5s. - Re-entrancy guard (CLAUDE_HOOK_DEPTH) and per-file edit counter. - Session-scoped finding dedup promoted from open question to v1. - Per-language inline-ignore syntax map (HTML/JSX/CSS/JS). - Hard-skip rules for sensitive paths and generated/lock files. - Honest framing about Claude Code lacking per-plugin hook disable. - Honest framing about Bash-written files being invisible in v1. - Codex Windows-not-supported call-out, feature flag note, trust ceremony detail. - Optional NDJSON audit log via IMPECCABLE_HOOK_LOG. - Findings cap lowered 8 → 5 with attention-budget rationale. - Versioned envelope ([impeccable@1]) on rendered template. - Expanded test plan, decision log, and stdin payload appendix. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(hooks): ship the design detector hook for Claude Code and Codex Implements docs/hooks-prd.md: a PostToolUse hook that runs the impeccable design detector after every Edit/Write/MultiEdit on a UI file and pushes findings into the agent's next-turn context as a short system reminder. Silent on clean files. Never blocks an edit. Why this matters: today, design slop (side-tab borders, gradient text, purple/cyan palettes, bounce easing, etc.) only gets caught when a human notices or someone explicitly runs /impeccable audit. The hook closes the loop at the moment slop is written. What ships in v1 - skill/scripts/hook.mjs: PostToolUse entry. Reads stdin, runs the detector in-process (no `npx impeccable` cold start), emits hookSpecificOutput.additionalContext when fresh findings exist. - skill/scripts/hook-lib.mjs: extracted helpers (config, cache, filter, render, audit log, runHook orchestrator). 100% unit-testable. - skill/scripts/hook-session-start.mjs: SessionStart greeting, gated by a project-scannable probe + 30-day throttle. - skill/scripts/hook-admin.mjs: backs /impeccable hooks on/off/status/ignore-rule/ignore-file/reset. Hardening built in - Re-entrancy guard (IMPECCABLE_HOOK_DEPTH) so the hook can never recursively spawn itself. - Hard-skip regexes for sensitive paths (.env, .pem, id_rsa, secrets, credentials, .git) and generated/lock/build output. These fire before the file is even read; cannot be turned off via config. - Path-traversal check on the inbound file_path. - Session-scoped dedup keyed by (session, file, rule, line) so the same finding never lands in context twice. Prevents the ~12.5K wasted tokens per chatty session called out in the PRD. - Per-(session, file) edit counter with a one-shot suppression notice on the 7th edit, silent after. - Fail-open contract: every error path returns exit 0 with no stdout. Optional NDJSON audit log via IMPECCABLE_HOOK_LOG. Three kill switches (precedence high to low): 1. IMPECCABLE_HOOK_DISABLED env var (1/true/yes/on, case-insensitive) 2. .impeccable/hook.json `enabled: false` 3. /impeccable hooks off slash command (writes the JSON) Inline ignores are language-aware. `// impeccable: ignore <rule>` for JS/TS, `<!-- impeccable: ignore <rule> -->` for HTML/Vue/Svelte/Astro, `{/* impeccable: ignore <rule> */}` for JSX/TSX, `/* impeccable: ignore <rule> */` for CSS. `*` matches any rule. Directive applies to the next non-blank line. Same shape as ESLint, Stylelint, Biome. Build pipeline - scripts/lib/transformers/hooks.js: per-provider hooks.json builders, plus the slim .codex-plugin/plugin.json manifest. - providers.js: emitHooks: 'claude' for claude-code, emitHooks: 'codex' for codex and agents. Codex also emits emitCodexPlugin. - factory.js: emits hooks/hooks.json next to the skills tree. - build.js: syncs hooks/ into harness roots and into the slim plugin/ subtree; writes .codex-plugin/plugin.json. Build is idempotent (verified: 98 staged files unchanged across two runs). Claude Code wiring uses exec form (command + args) and the ${CLAUDE_PLUGIN_ROOT} placeholder. Matcher: Edit|Write|MultiEdit. `if:` glob filters to UI extensions before spawning Node. PostToolUse timeout 5s, SessionStart timeout 3s. Codex wiring uses ${PLUGIN_ROOT} (Codex's native placeholder), matcher Edit|Write|apply_patch, no `if:` analog (the script does the extension filter). macOS and Linux only; hooks are disabled on Windows in current Codex builds. The trust ceremony and feature flag are documented in README.md. Routing - /impeccable hooks lives outside the 23-command router table on purpose: it is plumbing, not a design skill. The hidden routing slot is added to SKILL.md alongside pin/unpin so the LLM knows to dispatch it. The 23-command count and all stale-count validators remain happy. Tests - tests/hook.test.mjs: 38 unit tests covering env parsing, config load + defaults + malformed, cache round-trip + GC, ignoreRules/minSeverity/inline ignores (all four languages), globbing with **/*/{a,b}, render template with cap + clamp + 0-line prefix drop, audit log NDJSON, payload event-name parameterization, re-entrancy, kill switches, sensitive-path + generated-path + traversal skips, allowlist filter, config ignoreFiles, edit counter cycle including the 7th-edit notice, MultiEdit and apply_patch payload shapes, detector throw swallow, malformed stdin, missing file race. - tests/hook-build.test.mjs: 18 integration tests covering hook manifest shape (matcher, timeouts, exec form, if: glob, placeholders), Codex differences (${PLUGIN_ROOT}, no if:, no SessionStart), Codex plugin manifest (no inline hooks field to avoid the duplicate-file error), routing across the hooksJsonFor table, and presence of all three committed artifacts plus the bundled detector the runtime relative-import path depends on. Full suite: 175 bun tests + 186 node tests, all green. Docs - README.md: new "Design hook" section explaining default behavior, per-project / global / inline disable paths, the JSON schema knobs, the audit log debug flag, and the slop / a11y coverage split. - HARNESSES.md: flips the `hooks` row for Codex from No -> Yes (Claude was already Yes), adds a per-harness hook-surface table with the manifest location and matcher each provider uses. Open questions from the PRD intentionally deferred to v2: Bash-write blind spot, effort-aware suppression, Stop-hook session summary, per-rule severity, async hook mode. None block v1. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix Codex hook scanning: apply_patch paths and co-located stylesheets Parse file targets from Codex apply_patch command bodies, co-scan imported and sibling CSS when UI components are edited, drop the git-sweep PostToolUse group, and align Codex SessionStart manifest and trust docs with the official hooks spec. Co-authored-by: Cursor <cursoragent@cursor.com> * Gitignore hook session cache and drop local test HTML Hook dedup/throttle state in .impeccable/hook.cache.json is per-project runtime data like other .impeccable/ sidecars. Remove an untracked bad-nested-flexbox scratch page from site/public/. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix Claude Code hook: drop Edit-only if filter so Write/MultiEdit fire Claude's if permission rule binds to one tool name, so Edit(*.{…}) never spawned the hook on Write or MultiEdit despite the matcher listing them. Extension filtering now lives in hook-lib on both Claude and Codex. Co-authored-by: Cursor <cursoragent@cursor.com> * Surface Cursor design findings via stop-hook followup Replace dropped postToolUse additional_context with afterFileEdit recording and a one-shot stop followup_message so anti-pattern nudges reach the agent. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix design hook packaging and scans * Fix Cursor hook pending bucket fallback * Fix Sass hook scan coverage * Fix Cursor hook review findings * Fix session start dead hook normalization * Fix hook config and relative scan paths * Remove SessionStart design hook * Remove redundant afterFileEdit normalization * Fix Cursor suppression and module style scans * Fix sensitive path hook filter * Fix disabled Cursor stop hook emission * Refresh hook harness artifacts * Fix Cursor hook manifest install * Add hook ignore-value support * Ignore hook runtime files locally * Fix Codex plugin hook packaging * fix: address PR review bot findings Block numeric hook depth counters from re-entering. Avoid following stylesheet imports from traversal-looking hook targets. * fix: gate ignore-value suggestions by supported rules Only render exact ignore-value commands when the same finding can be suppressed by ignoreValues. * Package Codex plugin as hook-only * Remove Codex plugin packaging * Recover hook install probe plumbing * Remove Codex hook packaging follow-up doc * Remove extra hook docs and skill wording changes * Install real design hooks via skills CLI * Add provider hook smoke runner * Fix Cursor hook delivery with preToolUse gate * Simplify Cursor hook install to preToolUse * Clarify confirmed hook exceptions * Persist hook ignores in shared config * Guard font hook exceptions * Fix hook install after main rebase * Fix hook scan target handling * fix: address hook review findings * Address hook review feedback * Stabilize DeepSeek insert live fixture * Fix Cursor hook Python shell write bypass --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
4e251061b8 | Fix sr-only text overflow false positive (#197) | ||
|
|
f7f2bfc800 |
feat(detector): deprecate --fast (now a no-op, full scan always)
Since the jsdom removal the static HTML/CSS analysis is fast (~4ms/file) and covers every rule, so the regex-only `--fast` path only loses coverage (it ran ~10 of 41 rules) for no real speed win. It's a foot-gun: a `--fast` scan can read "clean" because most rules silently don't run. Deprecate gracefully rather than hard-remove: the flag is still accepted (so existing CI scripts don't break) but ignored, with a one-line stderr notice, and the full scan always runs. Dropped from --help and the example. Removed the `--fast` suggestion from the many-files warning and from critique.md's scan guidance. Ships to users via a CLI release (npm) and rides the next skill release in the bundled detector. Tests updated to assert the deprecation behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9ffd3211d5 |
Neo Kinpaku design system + Live Mode v3 (#169)
* Add neo kinpaku design system page * skill: rip out baked-in category recipes and saturated-default motion tropes Programmatic bias mining (impeccable-evals) traced four major defects back to specific lines in this skill that contradicted SKILL.md's own first-order-reflex warning: - brand.md "Pairing and voice" prescribed four category→aesthetic recipes (editorial → serif+sans, tech/dev/fintech → tight tracking, consumer/food/travel → script/display serif, creative → rule-break). These directly drove OpenAI's 76% extreme-negative letter-spacing on tech briefs and Anthropic/Google's 28-34% italic-serif-display slop on editorial/food briefs. Replaced with one sentence: the shape depends on the brand, not on the brand's category. - brand.md "Brand permissions" had "Typographic risk. Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines, a single oversize word as a hero." — a four-for-one slop driver behind 97% OpenAI comically-large H1, 42% bad-SVG illustration, and the editorial-italic slop. Deleted outright. - typeset.md and teach.md repeated the same category recipes; trimmed to the principle without the recipe. - SKILL.md Typography: added a hard hero-H1 ceiling (clamp() max ≤ 6rem ≈ 96px), with a <codex> block to make it explicit since OpenAI over-indexes here (97% ≥128px vs 24% for Anthropic). - animate.md, bolder.md, brand.md: removed "staggered reveals" and "scroll-triggered transitions" as the prescribed default ambitious motion. By 2026 that's the saturated AI tell, not a choreography. Reserved stagger for legitimate list-sibling rhythm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: anti-cream + codex-specific defect bans + universal slop bans Second pass after measuring more biases against the eval corpus. - SKILL.md Color: explicit "cream/sand/beige body bg is the saturated AI default of 2026" rule. Tone down the "tint every neutral" line so it doesn't read as "default to warm-tinted near-white" (which OpenAI hits at 74% and Anthropic at 31%-47%). - SKILL.md Absolute bans: add universal bans for two slop patterns detected at 55-95% across providers — tiny uppercase tracked eyebrow above every section (the 2023-era kicker that's now AI grammar) and numbered section markers (01/02/03). Also explicit "text that overflows its container is the universal defect on tablet/mobile." - SKILL.md Absolute bans → <codex> block: ban the GPT-specific defects Paul annotated repeatedly — `border:1px solid` + soft-wide-shadow (≥16px blur) "ghost cards", `border-radius:32px+` over-rounding, hand-drawn/sketchy SVG illustrations (loose-sketch / *-sketch classes, feTurbulence paper-grain filters), repeating-linear-gradient stripes, "X theater" AI-slop copy phrases. - SKILL.md Motion → <gemini> block: the image :hover transform tell (38% Google skill-on rate). Hover effects on images add no info; the image isn't an action target. Animate card chrome, not the image. - SKILL.md Typography: hard display letter-spacing floor ≥-0.04em (OpenAI defaults to -0.075em → cramped). Existing hero ceiling <codex> block extended with the letter-spacing rule. - codex.md Step A example: stop seeding "warm-grounded (deep oxblood + cream)" as the warm-palette template, which primes the cream default. - colorize.md Tinted backgrounds: stop printing the literal cream recipe `oklch(97% 0.01 60)`; replace with brand-anchored guidance. - document.md examples: warm-ash-cream → cool-paper so the example doesn't seed cream as the canonical neutral example. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: universal anti-slop bans + contrast/font-count/all-caps-body rules Third pass after measuring the rest of the cross-provider matrix: - Color: explicit "Verify contrast" rule. Low-contrast text fires at 68% across all providers skill-on (90+% off). The most common failure is muted gray body on a tinted near-white; light-gray-for- elegance is named as the single biggest cause of unreadable AI pages. - Typography: max-3-font-families rule. Overused-fonts (>4 families) fires at 28% Anthropic / 36% Google / 0% OpenAI skill-on; >50% off. Also: universal "no all-caps body copy" (moved from brand-only ban to Shared design laws since product-register also overuses caps). - Copy: anti-aphoristic-cadence ban targets Anthropic's signature "X. No Y." / "X. Just Y." voice (63% skill-on copy-slop rate, 77% off — the worst rate in the matrix). Once-is-voice / three-or-more- is-tell framing per the runner's copy-slop detector. - Copy: anti-SaaS-buzzword-string ban with the literal phrase list the detector watches for (streamline/empower/supercharge, trusted- by-leading, best-in-class/enterprise-grade/cutting-edge, etc). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strengthen anti-cream rule across full warm-neutral band Smoke validation showed the cream fix worked for Google + OpenAI but Anthropic Sonnet italian-restaurant still shipped `--paper: oklch(90% .018 88)` — cream just outside the L≥95% band the rule cited. Broaden the rule: - Band: OKLCH L 0.84-0.97, C < 0.06, hue 40-100 (was 95-97% / 60-95). - Name the token-name tells explicitly (paper / cream / sand / bone / flour / linen / parchment / wheat / biscuit / ivory) — the model defaults to one of these regardless of what hex it lands on. - Call out the specific brief patterns ("warm, traditional, family- coastal-Italian" / "editorial-restraint") that the model translates into cream by reflex. Then provide three explicit non-cream options: saturated brand color, true off-white at C=0, or darker mid-tone. Warmth in the brand is carried by accent + typography + imagery, not by body bg. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v3.2.0: skill bias-fix release Bumps version from 3.1.1 to mark the four-commit skill cleanup that rips out baked-in category recipes (brand.md), saturated-default motion tropes (staggered reveals everywhere), the cream/sand body-bg AI tell, codex-specific defects (1px+wide-shadow, over-rounding, hand-drawn SVGs, stripes, X-theater copy), the extreme-letter-spacing default, and universal slop bans (all-caps eyebrow on every section, numbered-section markers, all-caps body, font-family-count > 3, aphoristic copy cadence, SaaS buzzword strings). Plus a hard hero-H1 ceiling (clamp() ≤6rem) and a Gemini-specific image:hover transform block. Validated against ~190 post-fix samples — see impeccable-evals biases tab for per-provider deltas. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * drop "no pure black/white" rule entirely The rule was contested in the design world and causing more damage than good — pushing every page into the tinted-near-white default which is the cream/sand AI tell we already explicitly ban elsewhere. Vercel, SVKMS, Brutalist sites, et al. use pure black/white successfully; the skill shouldn't second-guess that. Skill markdown deletions: - SKILL.md Color: drop the "Never use #000 or #fff" bullet. - color-and-contrast.md: drop the "Never Use Pure Gray or Pure Black" subsection, the "Never pure black" table-row prescription, and the "Avoid: Using pure black for large areas" bullet. - colorize.md: drop the "NEVER use pure black or pure white for large areas" bullet. - polish.md: drop the "Tinted neutrals: No pure gray or pure black" half of the bullet (the gray-on-color bullet survives). Detector code (cli/engine): - registry/antipatterns.mjs: remove the `pure-black-white` entry. - rules/checks.mjs: remove the three `findings.push({ id: 'pure-black-white', ... })` emit points (inline #000 bg, Tailwind bg-black class, plain-HTML scan path). - engines/regex/detect-text.mjs: remove the two pure-black-white regex rules (CSS `background: #000…` + Tailwind `bg-black`). - detect-antipatterns-browser.js: regenerated via scripts/build-browser-detector.js. Tests: - detect-antipatterns-fixtures.test.mjs: invert the assertion that pure-black-white fires; expect it to NOT fire post-v3.2. Drop the Tailwind bg-black-opacity edge-case test (no longer relevant). - detect-antipatterns.test.js: drop the standalone "detects pure- black-white in styled-components" test and remove pure-black-white from the multi-detector assertions in PricingCard, globals.css, and GlobalStyle.tsx tests. 166 bun tests pass; 24 node fixture tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strip example patterns from copy rules, strengthen gemini block v3.2 rerun validation surfaced two issues: 1. Copy-slop detector fires more on Gemini under v3.2 (48% → 84%) than under no-skill baseline. Root cause: the anti-aphoristic-cadence rule printed the literal "X. No Y." / "X. Just Y." patterns as examples, and Gemini imitated them as the recommended voice. Same recipe-becomes- bias trap we hit with brand.md:116's "Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines" enumeration. Fix: describe the cadence as a rhythm ("serious statement, then punchy short negation") without printing literal patterns. Buzzword list trimmed to a single inline phrase family rather than quoted strings. 2. Gemini image:hover transform Gemini-tell hadn't dropped (31% off → 32% v3.2). Strengthen the <gemini> block: explicit "Never animate <img> elements on hover", call out the Tailwind group-hover:scale / group-hover:rotate / group-hover:translate parent-hover patterns by name (Gemini was reaching for these via Tailwind even though the prior text talked about :hover on the image directly). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: simplify context loading and inline register directive Replaces load-context.mjs's JSON output with a tight markdown block from the renamed context.mjs. The script now extracts PRODUCT.md's `## Register` field and appends a `NEXT STEP:` directive naming the matching reference (brand.md / product.md), which moved Gemini from skipping the register load entirely to honoring it. Drops the `.impeccable.md` auto-migration; makes IMPECCABLE_CONTEXT_DIR a lazy escape hatch consulted only when the default paths come up empty. Setup is now four bullets in one list. The DESIGN.md nudge is gone; in its place, a "familiarize with the existing design system" step that calls out CSS / tokens / running app as authoritative sources alongside DESIGN.md. The standalone `### Register` H3 stays for the cascade rules (task cue → surface → register field). New LLM-backed test suite at tests/skill-behavior/ runs five scenarios against claude-haiku-4-5, gpt-5.4-mini, and gemini-3.1-flash-lite via Vercel AI SDK. Captures real tool traces, asserts on context.mjs calls, brand.md loads, and teach.md fallback. Skips cleanly when API keys are unset. 13-14/15 pass; only stable failure is the v3.2.0-era gpt-mini S4 "don't re-run" regression. Adds @ai-sdk/google as devDep and the test:skill-behavior npm script. Touches em-dashes in skill/SKILL.md and four reference files so `bun run build:skills` passes its skill-prose validator. teach.md and document.md drop their "re-run the loader to refresh session cache" steps since the agent's own write is now the freshest source. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: merge orphan reference files into command sub-skills + inline S-tier invariants Two related restructurings: 1. SKILL.md now carries the cross-domain invariants that catch defects in any project (contrast/placeholder/gray-on-color, similar-font pairing, text-wrap, tabular-nums, centered-stack default, Flex/Grid choice, auto-fit grids, semantic z-index, reduced motion, stagger vs section-fade, premium motion materials, focus-visible, placeholders-aren't-labels, dropdown overflow trap, button/link copy). Greenfield-only rules (theme picking, color strategy, tinted neutrals) live under "New projects only". 2. Reference files merged into their command counterparts: - spatial-design.md -> layout.md - motion-design.md -> animate.md - color-and-contrast.md -> colorize.md - responsive-design.md -> adapt.md - ux-writing.md -> clarify.md - typography.md -> typeset.md (bolder.md redirected) - cognitive-load.md + heuristics-scoring.md + personas.md -> critique.md craft.md and shape.md "load references" lists updated to new file homes. interaction-design.md stays standalone (no 1:1 command verb). Net: 36 -> 27 reference files. Same content, fewer files, no orphaned reference loaded only from craft.md. Also extends the routing rules: if the user's first word doesn't match a command but the intent clearly maps to one, load that command's reference and proceed as if invoked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add sub-command + existing-project scenarios; move sub-command load to step 2 Adds three new LLM-backed scenarios to tests/skill-behavior: - S6: `/impeccable polish` → loads polish.md - S7: `/impeccable audit` → loads audit.md - S8: existing SvelteKit project (PRODUCT.md + DESIGN.md + src/app.css + src/lib/components/*.svelte + src/routes/+page.svelte) → agent reads at least one project code file to understand the existing design system S6/S7 surface a real model-floor: gpt-5.4-mini reads brand.md, reads the target index.html, and just does the polish/audit without ever loading the sub-command reference. Stronger SKILL.md wording didn't move it. Captured in the README baseline as a known weakness. Claude and Gemini honor the load reliably. To fix Gemini on S6/S7, sub-command reference loading is now Setup step 2 (right after context.mjs), not step 4 — placing it before the model gets focused on "doing the work". Step 3 (design-system familiarization) is tightened to require at least one project code read even when a sub-command reference loads in step 2, so Claude doesn't laser-focus on the sub-command flow and skip the broader exploration. Two new fixtures: MINIMAL_LANDING_HTML (a tiny static landing page for S6/S7) and SVELTE_PROJECT_FILES (a minimal SvelteKit scaffold with tokens, components, and a routes/+page.svelte for S8). Both designed to look real enough that agents treat them as production code. Suite is now 24 tests across three providers; baseline is 21-22/24, with the stable failures being gpt-5.4-mini scenarios 6 and 7. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add reveal-animation safety rule (must enhance, not gate visibility) Class-triggered visibility transitions pause on hidden tabs and headless renderers. The italian-restaurant smoke produced a build where 2 sections shipped opacity:0 because the CSS transition never advanced past currentTime=0 (timeline paused). Added one-liner under Motion to prevent the antipattern: reveals must enhance an already-visible default, never gate content visibility on a class-triggered transition. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: restore prescriptive cream/sand/beige paragraph Bisection across 5 historical skill commits on Gemini 3.5 flash fast lane n=3 found that |
||
|
|
e1d3ea0b6f |
Detector architecture v2: static engine, benchmarks, lab, and visual contrast (#156)
* Add detector benchmark lab and visual contrast fallback * Expand visual contrast fixture coverage * Add browser visual contrast fallback * Show visual contrast overlays in detector lab * Fix detector lab short viewport layout * Fix detector lab visual overlays * Add visual contrast to browser scan overlays * Avoid browser scroll jumps during visual contrast scans * Resolve visual contrast lazily on scroll * Refresh detector lab visual counts lazily * Update pnpm lockfile for static parser deps * Address Bugbot detector API comments * Report extension visual contrast errors * Refactor detector into engine modules * Address Bugbot detector comments * Fix latest Bugbot detector notes * Fix visual contrast fixture labels * Refine detector lab fixtures * Fix stale detector overlay references * Fix detector lab fixture URLs * Fix typography lab fixture highlights * Fix typography lab page-level signal * Fix visual overlay lifecycle cleanup * Remove dead spotlight timer cleanup * Make browser async APIs reject consistently |
||
|
|
e7e923c4ef |
Skill + craft cleanup, detector hardening, native subagent pipeline (#152)
* skill: drop quality tiers, keep the real brand-craft guardrails Codex's craft/brand pass introduced fast/ship/showpiece "quality bars" plus brand-specific build gates, asset ledgers, sub-agent review, and self-graded fallback labels. In practice those tiers became escape hatches rather than craft pressure: the final output should always be 10/10, and the real decision points are splashiness and maximalism, not quality. Removed: - All quality-bar / showpiece / fast / ship framing in shape.md and craft.md - Standalone Brand Direction (#4) and Asset Requirements (#10) sections in shape's brief; renumbered back to 1-10 - The Brand hard rules section in brand.md (folded its real prohibitions into the existing Imagery and Brand bans sections) - Brand-specific build-gate item, mock-fidelity bullet, production-bar bullet, present-step bullet in craft.md - Asset ledger ceremony in craft Step 4 - Review-only sub-agents and "self-reviewed fallback, not independently validated" machinery in craft.md and polish.md - The For brand surfaces, assess hard failures subsection in polish.md and the brand checklist row - tests/brand-showpiece-reference.test.mjs (and its package.json wiring) Kept (the real nuggets): - Asset-substitution prohibition: image-led briefs ship real/generated assets or canvas/SVG/WebGL, not generic CSS panels, cards, bullets, or copy - Repeated tiny uppercase tracked kicker labels as a brand ban - Detector/QA output is defect evidence only, never proof of quality - "What visual assets are real content here?" discovery question - Inspect each major section individually for brand and long-form work - repeated-section-kickers detection rule + fixture - CLI improvements (JSON to stdout, -json/-fast aliases, severity field) - critique.md: npx impeccable detect --json fix Harness output dirs refreshed via bun run build. Full test suite (186) passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strip gate ceremony; require shape pause; allow compact briefs The setup gate table and IMPECCABLE_PREFLIGHT banner pushed every craft run through ritual restatement (PRODUCT.md → original prompt → round 1 → round 2 → 70-line "confirmed brief" → critique → summary, all saying the same thing). Replaced with imperative prose that still demands the same work but skips the user-facing telemetry. Specifically: SKILL.md - Drop the Setup gate table and IMPECCABLE_PREFLIGHT banner. - Keep the imperative steps explicitly: load context, identify register and load brand.md or product.md, AND load the matching command reference (craft.md / shape.md / etc.) when a sub-command is invoked. The command-reference step is non-negotiable; without craft.md loaded the agent skips the shape-and-confirm pause. craft.md - Drop the Build Gate / Craft Contract formal sections; replace with one paragraph stating prerequisites. - Step 1 explicitly requires ending the response after presenting the shape output; the user must confirm before any code lands. Allows a compact 3-5 bullet brief when the prompt + PRODUCT.md already pin direction (full 10-section structure reserved for genuinely ambiguous tasks). - Step 3 image gate skips silently when image generation isn't natively available; no user-facing announcement. - Step 6 explicitly legitimizes "first pass clean, shipping" as a valid endpoint and bans inventing fake defects to demonstrate iteration. shape.md - Cap discovery at 1 round by default; second round only when first leaves material gaps. - Adds an "assert-then-confirm, not menu-with-escape" rule: when PRODUCT.md and the prompt make one option obvious, name it and ask for confirm or override instead of enumerating "Restrained / Committed / Or something else?" as a real choice. - Phase 2 brief has two forms now: compact (default for clear briefs) and full structured (genuinely ambiguous). Open Questions can't double as leading-with-Recommend; if you'd write "Recommend: X", decide X. - Image gate same as craft.md. Validated end-to-end with a Haiku skill-on observability run: agent loads craft.md plus the brief's recommended implementation refs, pauses for one productive question (accent color, trace fidelity, CTA), and ships an artifact with zero side-tab violations vs. the original v1 baseline. Cost trades up modestly for that quality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * craft.md Step 6: Reading the screenshot is the inspection, not taking it A v4 eval run took 4 targeted screenshots (hero, mobile, tablet, query-section) and then never Read any of them back. The agent treated browser_screenshot itself as "I inspected" and shipped without the multimodal feedback loop ever closing. Detector caught the resulting slop (5+ side-tab violations) on adjacent runs that did the same thing. Step 6 now spells out the pattern explicitly: take the screenshot, then Read the resulting PNG so its image content enters the conversation as multimodal input, then critique what you actually see in the image. With a check: "if your critique could have been written without looking at the image, you didn't look at the image." Validated with v5b: agent took 6 screenshots, Read all 6 back, and shipped with zero detector findings (vs the previous greenfield runs that hit 1-12 findings each). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * craft + brand: framework foundation, build-pipeline respect, image verification Three closely-linked additions surfaced by an eval-harness session investigating why the agent always shipped flat single-file HTML and zero imagery on greenfield brand briefs. 1. craft.md gains a new Step 0 "Project Foundation" before Shape. Detects existing framework / component library / icon set and uses what's there. Greenfield: ask the user via AskUserQuestion with sensible defaults framed by the brief (Astro for content/ brand sites, SvelteKit/Next/Nuxt for app surfaces, single index.html only for one-shot demos). Skipping the framework decision and writing flat HTML "to satisfy the spec" produces work that reads as a 2018 prototype regardless of visual quality. 2. craft.md Step 5 production bar gains two bullets: - Respect the build pipeline. Edit source files and run the project's `npm run build`; do not write to build/ / dist/ / .next/ directly with cat/heredoc/Bash redirects. Bypassing the pipeline skips asset hashing, image optimization, code splitting, and CSS extraction. - Verify external image URLs before referencing them. Use an image-search MCP, web-fetch tool, or browser if available; guessed photo IDs ship as broken-image placeholders. 3. brand.md "Imagery" section: - Generalizes the Unsplash URL guidance to "verify URLs before referencing them" with a hierarchy: image-search MCP > web-fetch > confidence-restricted manual selection > fewer photos. - Tightens the tech/dev-tool exception. Old line "zero imagery can be correct" gave models a permission slip. New framing keeps the underlying truth (typography + code + diagrams primarily carry voice) but raises the floor: imagery still earns its place when it serves the brief, and skipping it requires naming the typographic/diagrammatic move that's carrying the visual weight instead. "Zero imagery is the failure mode of laziness, not restraint." Eval-harness corpus that prompted this: 19/19 brand landing tasks shipped 0 images each, including ones where Opus had taste enough to break the dev-tool color default lane. The skill needs to teach both halves of the decision; the harness shouldn't have to nudge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * detector: body-text-viewport-edge rule + OKLCH/var-resolution + anchor-inherit FP fixes New rule: body-text-viewport-edge flags body paragraphs that render flush against the left/right viewport edges (no container padding). Tested via the new tests/fixtures/antipatterns/body-text-viewport-edge.html fixture (3 flag cases, 5 pass cases) and the test in detect-antipatterns-browser. False-positive class fixes — all jsdom-mode only (real browsers resolve the cascade correctly so these gates stay inert there). Five related gaps that compounded into ~14× spurious contrast findings on Tailwind v4 pages with OKLCH color tokens: • OKLCH parser. jsdom returns the literal "oklch(...)" string from getComputedStyle; the detector now converts to sRGB via Björn Ottosson's matrices. Handles Tailwind v4's compact minified form "oklch(21.5%.02 50)" (no space after %). • var() resolution. resolveBackground + checkElementColors now accept the existing customPropMap and parse `var(--color-paper)` etc. as proper RGB via the new parseColorResolved helper. • bg-color before bg-image. The old order bailed on any gradient ancestor before checking for a solid background-color underneath, causing the body's decorative paper-grain gradient to be measured against instead of the page's actual `bg-paper` cream. • body/html-level gradient → white fallback. When the only opaque ancestor we can read is body/html with a gradient overlay (and jsdom can't decompose `background: var(--paper) gradient` to extract the solid color), return white instead of falling through to resolveGradientStops — which was picking up paper-grain noise colors and using them as the bg. • Anchor-inherit workaround for jsdom :link UA specificity. Tailwind v4's preflight declares `a { color: inherit }` (0,0,1). jsdom's UA stylesheet has `:link { color: blue }` at (0,1,1) and wins the cascade. Real Chrome wraps :link in :where() (0,0,0) so the page rule wins. When the page declares the inherit rule AND we see jsdom's default `rgb(0,0,238)` on an anchor, walk to the nearest non-anchor ancestor and use its color. • Alpha-fallback safety gate. When text has alpha<1 AND we couldn't find an opaque ancestor (effectiveBg null), skip the contrast finding. Covers any remaining FP class the deeper fixes miss. Verified end-to-end against an Opus iter-1 artifact on Tailwind v4 with 14 cream/cream FPs + 2 blue-link UA FPs before; 0 findings after, while the color.html fixture's 12 real low-contrast cases continue to flag (verified via direct detectHtml calls). cli/engine/detect-antipatterns-browser.js is the generated browser distribution — regenerated from .mjs via scripts/build-browser-detector.js (no manual edits to the generated file). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * craft.md: tighten verbose passages, de-codex Step 6, cut redundancies Cumulative reduction: 218 → 155 lines (-29%). Step 0: drop the "Why this matters" paragraph at the end. The body of Step 0 already makes the framework-pick point; the paragraph just re-explains it with extra rhetoric. Step 1: replace the 4-sentence "you must end your response" block with a single line. The original said the same thing three different ways. Step 3: trim the conditional / defensive scaffolding (Purpose subsection, "do not skip because the eventual UI is semantic..." paragraph, duplicated approval-loop guidance). Mock fidelity inventory preserved. Step 4: drop the "keep UI text semantic" sentence; it duplicates Step 5's "Semantic first" rule. The rasterized-vs-semantic decision rule stays. Step 5: tighten each production-bar bullet to bold-lead + specifics format. All 15 rules preserved (real content, mock ingredients, semantic first, spacing/alignment, typography, state coverage, interaction quality, icon set, build pipeline, image URL verification, optimized imagery, premium motion, maintainability, technical cleanliness, ask-when-uncertain). Step 6: rewrite around "look at what you built like a designer would — your eyes are whatever the harness gives you." Drops Codex-specific "In Codex, use browser-use" bias. Drops the verbose 3-step Read pattern (condensed to one sentence). Drops the 1-8 numbered checklist (replaced by a tight paragraph). Keeps the load-bearing rules: read the PNG, don't fabricate iteration, mock fidelity reference, exit bar = studio defensibility. Step 7: drop the closing "Iterate based on feedback. Good design is rarely right on the first pass" preachy filler. All em-dashes converted to semicolons / colons / periods to satisfy the skill prose validator. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build: native subagent pipeline + Codex-only asset producer Adds an agent cross-compile pipeline alongside the existing skill pipeline. Sources live at skill/agents/*.md; providers that declare agentFormat (codex-toml, claude-md) emit native subagent files. An optional providers: <list> field on an agent gates which harnesses get a copy; default (no field) ships everywhere. The impeccable-asset-producer agent is opt-in to Codex only. It's useful for Codex's native image generation path and is untested elsewhere; Claude has no native image gen anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * brand: inverse-test + cultural-symbol palette guardrail Two additions to the brand register reference: - Inverse slop test: describe the page the way a competitor would describe theirs. If that sentence fits the modal landing page in the category, restart. - Palette guardrail: when a cultural-symbol palette is the obvious pull, reach past it. Let cultural reading come from typography, imagery, and copy. Harness mirrors regenerated; some also catch up to the image- verification paragraph from |
||
|
|
e587004ee4 |
Refactor: cleaner top-level directory structure (#138)
* refactor(content): merge content/site/ into site/content/ Phase 1 step 1 of the directory restructure. The dual content tree was called out in CLAUDE.md as cleanup; both trees were already in sync except for anti-patterns-catalog.js, which moves to site/data/. - Delete content/site/skills/ and content/site/tutorials/ (duplicates of site/content/, which is what Astro's content collection actually reads). - Move content/site/anti-patterns-catalog.js -> site/data/. - Update scripts/lib/sub-pages-data.js and scripts/build.js to read from site/content/ and site/data/. - Drop content/site/ from validateProse target list (site/content was already there). - Rewrite the "Two content trees" section in CLAUDE.md as a single-tree pointer; update stale dev-server text mentioning the deleted server/index.js. Tests: 186/186 pass. Skills build: clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(skill): rename source/skills/impeccable/ -> skill/ Phase 1 step 2 of the directory restructure. The path was redundantly nested ("source/" wrapper plus "skills/impeccable/" — singular content hidden behind the plural). Collapses to flat skill/SKILL.md + skill/reference/ + skill/scripts/. - Move source/skills/impeccable/ -> skill/. - Rewrite scripts/lib/utils.js readSourceFiles(): drop the multi-skill iteration (CLAUDE.md commits to a single user-invocable skill); read skill/SKILL.md directly. - Update scripts/build.js, scripts/generate-og-image.js, and the sub-pages data layer to point at skill/. - Update tests/lib/utils.test.js: drop the "multi-skill" and "dir-name fallback" cases, update single-skill paths to skill/. - Update tests/build.test.js similarly: drop "multiple skills" integration test, update paths. - Update non-glob path joins in tests/framework-fixtures.test.mjs, tests/live-e2e/session.mjs, tests/live-e2e/agents/llm-agent.mjs, tools/live-loop.mjs. - Update prose/text references in CLAUDE.md, AGENTS.md, DEVELOP.md, README.md, scripts/lib/sub-pages-data.js, bin/commands/skills.mjs, site/data/anti-patterns-catalog.js, site/pages/docs/[...slug].astro, docs/adr-live-variant-mode.md, docs/plans/. Eval framework note: the separate impeccable-evals repo reads ../impeccable/source/skills/impeccable/ and needs a coordinated rename to ../impeccable/skill/. Tests: 186/186 pass. Skills build: clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: rename docs/ -> notes/ Phase 1 step 3 of the directory restructure. The internal docs/ dir (ADRs and plans) clashed with the site's /docs route. Renaming it "notes/" makes the difference unambiguous: notes/ is project-internal process, /docs is the user-facing route under site/pages/docs/. No code references the dir; the rename is a clean git mv. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(site): move public/ under site/public/ Phase 2 step 4 of the directory restructure. Public assets and the Astro publicDir now live alongside the rest of the site, so site/ is fully self-contained for static content. - git mv public site/public. - astro.config.mjs: add publicDir: './site/public'. Astro defaults to ./public at the project root, so the override is required. - scripts/build.js: write generated _data, _headers, _redirects, _routes.json, and js/detect-antipatterns-browser.js into site/public/. Also delete the dead _REMOVED() Bun static-site builder (replaced by Astro at #130; the placeholder no longer earns its keep). - scripts/build.js validateProse: replace the stale public/index.html reference (deleted at the Astro migration) with site/pages/index.astro in the count-validation file list, restoring homepage drift detection. - scripts/generate-og-image.js: write OG image into site/public/. - scripts/screenshot-antipatterns.js: read examples from + write screenshots to site/public/antipattern-{examples,images}/. - scripts/lib/sub-pages-data.js: load command demos from site/public/js/demos/commands. - .gitignore: rename the public/* generator-output entries to site/public/*. - CLAUDE.md: refresh CSS/data-file paths (still pointing at the old pre-Astro public/css/ + public/js/ tree), point the changelog and command-add checklists at site/pages/index.astro and site/scripts/data.js + site/scripts/components/framework-viz.js. Cloudflare Pages note: functions/ stays at the repo root because CF Pages auto-discovers it there with no configuration knob to relocate. Moving it under site/ would either break deployment or require a build-time copy step that adds more complexity than the cleanup is worth. Tests: 186/186 pass. Skills + site build clean. _headers, _redirects, _routes.json, _data/ all land in build/ correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): consolidate bin/ + src/ + lib/ under cli/ Phase 2 step 5 of the directory restructure. The CLI surface was split across three top-level dirs whose names were easy to mistake for each other (especially src/ vs source/ pre-step-2). Consolidates under cli/. - git mv bin -> cli/bin (CLI entry + skills sub-command) - git mv src -> cli/engine (detect-antipatterns engine + browser variant) - git mv lib -> cli/lib (download-providers helper) Update package.json: - bin.impeccable: cli/bin/cli.js - main + exports: cli/engine/detect-antipatterns.mjs and the ./browser variant - files: ["cli/", "LICENSE"] Update internal references: - cli/bin/cli.js: dynamic import points at ../engine/, package.json read goes one level deeper (../../package.json). - functions/api/download/[type]/[provider]/[id].js + bundle/[provider].js: cli/lib/download-providers.js path. - scripts/build.js, scripts/build-browser-detector.js, scripts/build-extension.js: cli/engine path constants. - scripts/lib/sub-pages-data.js, scripts/lib/utils.js, skill/scripts/ live-server.mjs: comment refs. - tests/detect-antipatterns{,-browser,-fixtures}.test.{js,mjs}, tests/windows-path-fix.test.js: import + read paths. - AGENTS.md, CLAUDE.md: doc paths. Verified: - npx node cli/bin/cli.js --version, --help, detect --help all work. - bun run build, bun run build:browser, bun run build:extension all clean. Browser detector lands at cli/engine/detect-antipatterns-browser.js; extension/detector/detect.js still emits to the same location. - bun run test: 186/186 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: update browser-detector paths missed in cli/ rename Bugbot caught two runtime path leaks where the comment got renamed to cli/engine/ but the actual code still used the old src/ segment. - skill/scripts/live-server.mjs: detectPaths array now joins cli, engine, detect-antipatterns-browser.js for both the repo-relative lookup (4 dirs up from .claude/skills/impeccable/scripts/ to repo root) and the npm node_modules fallback. Without this fix, the detection overlay would silently not load during live-server sessions. - scripts/build.js: the post-build copy of the browser detector into site/public/js/ was reading from src/. The if (fs.existsSync(...)) guard meant the copy was silently skipping, so antipattern-examples pages would 404 on /js/detect-antipatterns-browser.js once the site was deployed. Tests: 186/186 pass. Build clean. site/public/js/detect-antipatterns-browser.js re-emits as expected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: cleanup-deprecated import path missed an extra .. in cli/ rename Bugbot caught three call sites in cli/bin/commands/skills.mjs that import '../../skill/scripts/cleanup-deprecated.mjs'. Pre-rename, that was correct from bin/commands/ (one parent to bin/, one to repo root). After moving the file from bin/commands/ to cli/bin/commands/, the path is one directory deeper, so it needs three .. segments to reach the repo root. Without the fix, every cleanup invocation throws on import and gets swallowed by the surrounding try/catch — silent skip. cli/bin/cli.js's package.json read already uses '../../package.json' (the same depth pattern), confirming three levels is correct. Verified: dynamic import resolves and exports the expected functions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: sweep stale path/file references missed in the restructure Same root cause as the two bugbot finds: some references in moved or related files weren't tracked because they didn't match a simple sed pattern. Caught the rest by walking each moved dir's depth and each Astro-migration deletion. Stale path references (post-Astro migration, missed earlier): - CLAUDE.md: legacy URL redirects "live in server/index.js" -> point at the actual sources (scripts/build.js generateCFConfig + site/public/_redirects). - AGENTS.md: counts.js path (public/ -> site/public/), changelog file (public/index.html -> site/pages/index.astro), screenshots note (public/ -> site/), source-of-truth dirs (source/, src/ -> skill/, cli/). - tests/detect-antipatterns-browser.test.mjs: comment about routes "in server/index.js". - skill/reference/live.md: workflow.css example for "this repo" was pre-Astro (public/css/) -> site/styles/. (User-project Vite/Next example unchanged.) Stale path that pointed at moved files: - tests/skills-cli.test.js: CLI path was '..', 'bin', 'cli.js'; now '..', 'cli', 'bin', 'cli.js'. Test isn't wired into bun run test but it would have failed if invoked. Dead files (orphaned by Astro migration, never cleaned up): - tests/server/download-validation.test.js: imported from ../../server/lib/{validation,api-handlers}.js which were deleted in |
||
|
|
b5c203f38a |
feat(detector): flag Fraunces, Geist, and the new monoculture fonts
Adds Fraunces, Geist (Sans/Mono), Mona Sans, Plus Jakarta Sans, Space Grotesk, Recoleta, and Instrument Sans to OVERUSED_FONTS. Brand-domain exceptions for Geist on vercel.com / nextjs.org / v0.app and Mona Sans on github.com / githubnext.com. Updates four should-pass fixtures that used the now-flagged faces as "good examples"; switches to Newsreader + Karla. Adds positive assertions for Fraunces and Geist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
3c9cc86061 |
Merge CLI into main repo, switch everything to Apache 2.0
Merges the impeccable-detect CLI repo (pbakaus/impeccable-cli@831a6cc) into this repo. The BSL-1.1 license that motivated the split is gone; everything is now Apache 2.0. - Add bin/, src/, detection tests and fixtures from CLI repo - Merge package.json: name → "impeccable", add bin/exports/files fields - Internal refs now read from local src/ instead of node_modules/ - Update SPDX headers, NOTICE.md, CLAUDE.md, FAQ, npm README - Add prepack/postpack scripts for CLI-focused README on npm - Remove terminal license labels (no longer needed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
3974789903 |
Remove detection engine files, now in @impeccable/detect package
Remove all detection engine source, tests, fixtures, and build scripts that have been extracted to the @impeccable/detect package (BSL-1.1). - Delete source/skills/critique/scripts/ (detect-antipatterns.mjs, browser.js) - Delete scripts/build-browser-detector.js - Delete tests/detect-antipatterns*.test.* and tests/fixtures/antipatterns/ - Delete .claude/skills/critique/scripts/detect-antipatterns-browser.js - Update scripts/build.js to read detection count from npm package - Update server/index.js to serve browser script from npm package - Update CLAUDE.md to reference @impeccable/detect - Update package.json test script (detection tests removed) - Update .gitignore (remove obsolete browser script entry) - Rebuild all provider skill distributions with updated critique skill Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
8d05411c3e |
Harden CLI detection for framework files, multi-file projects, and dev servers
Tier 1: Add Vue/Svelte <style> block extraction and CSS-in-JS template literal detection (styled-components, emotion) so anti-patterns inside framework-specific syntax are caught. Enable multi-line context for CSS files so cross-line patterns like gradient-text are detected. Tier 2: Build a lightweight import graph when scanning directories. Findings are annotated with importedBy context (e.g. "imported by App.tsx") in both human and JSON output. Tier 3: Detect framework config files (Next.js, Vite, SvelteKit, Nuxt, Astro, Angular, Remix), probe the dev server port with HTTP fingerprinting to distinguish the expected framework from unrelated services, and suggest URL-based scanning for more accurate results. Adds realistic Next.js project fixtures (Tailwind, CSS Modules, styled-components) plus Vue, Svelte, JSX, and CSS-in-JS unit fixtures. 158 tests, 356 assertions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
4d2ef64935 |
Fix glow/gradient detection, fix test performance (280s -> 5s)
Detection improvements: - Remove SAFE_TAGS from glow check (buttons/links with glows are valid) - Add gradient color parsing (parseGradientColors) for AI palette detection on gradient backgrounds including buttons - Detect cyan neon text on dark backgrounds as AI palette - Resolve gradient backgrounds as dark for glow detection - Fix pure-black false positive on semi-transparent overlays (a >= 0.9) - Skip low-contrast/gray-on-color when background is a gradient - Fix "Only font:" double-colon in browser labels Test performance: - Split jsdom fixture tests to Node's test runner (bun + jsdom hangs after ~13 instances due to resource leak) - bun test for unit/regex/CLI tests (94 tests, 4s) - node --test for jsdom fixtures (15 tests, 1.3s) - Total: 109 tests in ~5s (was 280s+) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c751015fa1 |
Add motion and dark-glow anti-pattern detection (15 → 16)
New detections: - bounce-easing: flags bounce/elastic animation names, animate-bounce (Tailwind), and cubic-bezier curves with overshoot (y values outside [0, 1]) - layout-transition: flags explicit transition of width, height, padding, margin, and max-height/min-width variants; skips transition: all - dark-glow: flags colored box-shadow with blur > 4px on dark backgrounds (luminance < 0.1); skips gray shadows, focus rings (no blur), and non-dark backgrounds Includes 48 new tests across unit, regex, and jsdom fixture tests with dedicated should-flag and should-pass HTML fixtures for both categories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
add8c1958d |
Fix nested card detection: innermost-only, lower threshold, raw style fallback
Three fixes: - Only flag innermost nested cards: if L1>L2>L3, only L3 gets flagged (not L2). Uses ancestor-filtering after collection pass. - Lower text threshold from 20 to 10 chars to catch short card content like "Inner card via CSS." - isCardLike now also checks raw inline style attribute for box-shadow and border-radius (jsdom doesn't resolve CSS shorthands). Tightened heuristic: shadow or border is mandatory (not optional). Fixes false positive on layout-should-pass where a tinted subsection (rounded + bg, no shadow) inside a card was incorrectly flagged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
f90e640892 |
Fix nested card detection, drop identical-card-grid
- Nested cards: fixed dedup to use WeakSet on actual elements instead of tag-name key, so all nested card instances are found (not just the first div-in-div pair). Now catches all 4+ nesting examples. - Dropped identical-card-grid: too many legitimate uses (data displays, pricing cards, navigation tiles) make false positives unavoidable. - Removed from CLI, browser script, tests, and ANTIPATTERNS registry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
72b9ca2941 |
Add layout anti-pattern detection: nested cards, identical grids, spacing, centering
Four new layout detections: - nested-cards: jsdom DOM walk finds card-like elements (shadow + rounded + bg) nested inside other card-like elements. Excludes dropdowns (absolute/fixed), form inputs, code blocks, badges (<20 chars), and known component classes. - identical-card-grid: detects grid/flex parents with 3+ children sharing the same structural fingerprint (icon + heading + paragraph template pattern). - monotonous-spacing: regex on raw HTML collects padding/margin/gap values (px, rem, Tailwind classes), rounds to nearest 4px, flags when >60% use the same value with <=3 distinct values. - everything-centered: regex counts text-align:center and Tailwind text-center on text elements, flags when >70% of 5+ text elements are centered. Also narrowed pure-black-white to only flag #000 as background color — text-black, text-white, bg-white, and #fff are no longer flagged (too common, per user feedback). Extensive should-pass fixture covers: shadcn card sub-components, cards with form inputs/dropdowns/code blocks/badges/accordions/tabs/images, pricing cards, varied spacing, mixed centered/left-aligned layouts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
8a357d4754 |
Add color and contrast anti-pattern detection
Five new detections: - pure-black-white: flags #000/#fff in styles via regex (jsdom bg resolution unreliable for this) - gray-on-color: gray text (low chroma, mid luminance) on colored backgrounds via getComputedStyle + ancestor bg walk - low-contrast: WCAG AA violation (4.5:1 body, 3:1 large text) via computed contrast ratio with resolved effective background - gradient-text: background-clip:text + gradient combo via regex (jsdom doesn't compute background-clip) - ai-color-palette: conservative purple/violet accent detection via regex on known hex values in prominent contexts Background resolution handles jsdom limitation where background shorthand isn't decomposed — falls back to parsing raw style attribute for hex colors. Color fixtures added for both should-flag (all 5 types) and should-pass (tinted neutrals, good contrast, non-purple accents). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
ed1579ee37 |
Skip page-level checks on partials/components
Page-level typography checks (flat hierarchy, single font, overused font) now only run on files that look like full pages (have <!DOCTYPE, <html>, or <head> tags). Partials and components still get element-level border checks. isFullPage() strips HTML comments before checking to avoid false matches on prose that mentions tag names. Added partial-component.html fixture that has Inter, flat sizes, and a side-tab border — verifies only the border is flagged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
37393f1793 |
Normalize detection to jsdom by default, regex as fallback
Architecture simplified to two paths: - HTML files: jsdom with getComputedStyle (resolves linked CSS, cascade) - Non-HTML files: regex fallback (CSS, JSX, TSX, etc.) - URLs: Puppeteer (unchanged) - --fast flag forces regex-only for all files Removed --deep flag (jsdom is now the default). Removed static mode from browser script (always uses getComputedStyle — it's in a real browser). Anti-pattern definitions split into: - checkElementBorders() — shared element-level computed style checker - checkPageTypography() — shared page-level checker - REGEX_MATCHERS/REGEX_ANALYZERS — regex fallback for non-HTML Browser script simplified from 470 lines to 250. CLI script reduced from 810 lines to 440. Detection logic is now single-source for jsdom/puppeteer/browser. Fixtures now served via /fixtures/* route in dev server for proper CORS handling of linked stylesheets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
32a54138bb |
Add deep detection via jsdom and URL scanning via Puppeteer
Three detection tiers: - file/dir (default): fast regex scan, zero dependencies - file + --deep: jsdom computed styles, resolves linked local stylesheets by inlining <link rel="stylesheet"> content before parsing - URL (https://...): auto-launches Puppeteer for full browser rendering, handles CDN stylesheets, JS-rendered content, everything New exports: detectAntiPatternsDeep(), detectAntiPatternsUrl() jsdom added as devDependency; puppeteer remains optional (npx cache). TDD: linked-stylesheet fixture demonstrates the gap — regex finds 0 border issues, --deep correctly catches side-tab and top-accent from the external CSS file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
1fb896a3ff |
Add typography anti-pattern detection: overused fonts, single font, flat hierarchy
Three new detections: - overused-font: flags Inter, Roboto, Open Sans, Lato, Montserrat, Arial as primary font-family or via Google Fonts imports - single-font: file-level analyzer flags pages using only one non-generic font family (needs pairing for typographic hierarchy) - flat-type-hierarchy: file-level analyzer collects all font-size values (px, rem, Tailwind text-* classes, clamp min/max) and flags when the max/min ratio is below 2.0 Detection engine extended to support file-level analyzers alongside line-level matchers. Typography fixtures added for both should-flag and should-pass cases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
f9bfe18d26 |
Add anti-pattern detection CLI, browser visualizer, gallery page, and build DRY refactor
- Anti-pattern detector script (source/skills/critique/scripts/detect-antipatterns.mjs): CLI tool that scans files/dirs for UI anti-patterns via regex. Detects side-tab accent borders and border-accent-on-rounded patterns across Tailwind, CSS, JSX. Context-aware: skips safe elements (blockquotes, nav, inputs, code), neutral colors, and adjusts thresholds based on border-radius co-occurrence. - Browser visualizer (public/js/detect-antipatterns-browser.js): Drop-in script that highlights anti-patterns directly in the browser with labeled overlays. Two modes: "static" (regex, matches CLI) and "computed" (getComputedStyle, catches CSS cascade). Scans both inline styles and <style> blocks. - Gallery of Shame (public/gallery.html): Standalone page showcasing 11 AI anti-pattern examples with thumbnails and links. Anti-pattern example pages updated from 1080x1080 Twitter format to responsive layouts, labels removed, screenshots retaken at 16:10. - Critique skill updated to run detector before manual review. - Build system: skills now support scripts/ directories alongside reference/. All 8 provider transformers refactored to use shared.js (DRY). - 58 new tests covering detection logic, fixtures, CLI integration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |