mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 14:16:28 +03:00
79c648a9ab5a4da22aa1d89340f51901592b770d
16
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ae56d719af |
Name the image-gen sources and the unanswered default
Two review findings on #583. "context.mjs reports it" undersold what counts: that directive only fires on an OPENAI_API_KEY, so a harness with a native image tool and no key generates images while the boot output says nothing. Read literally, the step would skip the question exactly where the toggle belongs. It now names both sources and says a silent boot is not evidence. The unanswered branch said to state which path the session takes without saying which one it is. Left implicit, an agent picks its own, which is the failure this step exists to stop. It now names comp-first, the default new-work applies when nothing is recorded. Written with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
83e8b4645c |
Ask the build path as its own question, and record only a real answer
A live Codex session folded the build path into the stack question as a
trailing recommendation ("I recommend static and code-first"), never said what
either name means, treated its own recommendation as the user's answer, and
wrote `buildPath: code` as a standing default. The user disagreed and flipped
the board to comp-first, but a flip binds one session, so the unasked default
stayed on disk to steer every later round.
Step 5 said to "ask once ... stated as the trade it is", which the run
violated, but the step left the shortcut open: it sits after the interview
ends, it never says a recommendation is not an answer, and unlike the stack
question it offers no way to end without a value, so an agent holding no answer
writes one anyway.
Now: it is its own question, never a clause inside another; the trade is stated
in the question the user reads, because the two names mean nothing on first
contact; only the user's own choice is written; and an unanswered question
records nothing and says so. Unset is a working state, since the page toggle
governs the session and new-work's one-time offer still captures the answer at
the first flip.
The same run also wrote "Code-first build path" into PRODUCT.md's `## Stack`,
so the step now says the config is the only place this lives: a copy in product
truth outlives the setting and steers rounds nobody can trace back to it.
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
c489335799 |
Build path becomes a config key existing projects can actually reach
The build-path preference shipped as a question only `init` asks, written to a file only `init` writes. Nothing routes an initialized project back through init, so every existing project took the comp-first default without anyone choosing it, and the only recourse was a footer toggle that binds one session. Neither the setting nor the round that preceded it ever reached a release (skill-v4.0.4 has no `buildPath`, no `comp-led`, no `.impeccable/settings.json`), so the PRODUCT.md standing-commitment fallback describes an era that never existed publicly. It is deleted rather than honored: told a field might exist, models go hunting for it and preserve it. - `buildPath` moves from `.impeccable/settings.json` into the unified `.impeccable/config.json`, which already has a known-keys registry, doctor coverage, and a gitignored `config.local.json` override. Whether a machine has an image tool is a property of that machine, so the local file wins. - new-work captures the answer from behavior instead of an interview: a toggle flip on a project recording nothing asks once, after the round closes, whether to keep it. The answer is written either way, because a declined offer nothing writes down is an offer the next session makes again. - Two findings: `config-invalid-build-path` (an unread value rides the default rather than the opposite path) and `config-build-path-unset`, gated on a product record plus evidence of direction work so polish-and-audit projects never hear about a setting they do not use. - init treats a recorded value as a confirmed answer, resolving its conflict with Step 1's "do not reopen confirmed fields". - The setting was undocumented in the README and doctor.md. Both now cover it. Also records a measured skill-behavior baseline. Three cells fail on unmodified main (scenarios 9 and 15, `initialized natural build`), verified against a clean worktree; the suite README now says so, so the next person does not spend the hour attributing them to their own branch. Written with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
64dd60a78a |
Build path becomes a setting plus a page toggle; the followup contract round retires
- serve-question: payload buildPath { value, toggle } renders a footer
segmented control (comp first / code first) with the trade stated in one
line; the default comes from settings, a flip binds that session only.
Code-led rounds treat declared comp paths as flip reserves: wireframes
render, a flip to comp shimmers the slots and surfaces once through
--wait as BUILD PATH FLIPPED so the agent starts generating mid-round;
the flip back is free and a landed comp stays. The ANSWER carries
buildPath and buildPathFlipped with a session-only directive.
- init Step 5 asks the preference once (only when image generation exists)
and writes .impeccable/settings.json; context.mjs surfaces the recorded
default every session; PRODUCT.md standing commitments stay honored as
the fallback.
- new-work retires the two-card execution-contract round: no round asks a
workflow preference. followup stays as the generic same-table mechanism.
- e2e: new toggle test (14/14 with the wireframe test).
Written with AI assistance (Claude Code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
430d74a12b |
The stack is the user's decision, and code is a medium of ambition
Two field observations. Greenfield projects with no framework never got asked what to build on: the interview covered product truth and banned aesthetic questions, and the model silently picked a scaffold the user never chose. Init now asks once, static HTML, a named framework, or a delegated choice plus any deploy constraint, and records the outcome under a new optional Stack section, including the delegation itself, so later work knows the choice was offered. And the medium guidance named raster a dozen times while naming WebGL once, so models never reached for vector or GPU code unprompted. The affinity now runs both ways at the decision point: precise geometry, shape systems, diagrams, expressive motion, shaders, and anything interactive are vector and GPU territory, where a raster flattens what should move, scale, and respond. The sketchy-SVG ban states its own scope: it bans SVG imitating pictures, never SVG doing geometry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6e8cdfa581 |
Counter the harness autonomy directive from inside the working turn
A traced Claude Code injection asserts for whole model families that the user is not watching and cannot answer questions; it ships default-on with no off switch, and it suppressed every interactive step of a live run (interview skipped, PRODUCT.md inferred, decision page never served). Prose in a reference file loses that argument, placement wins it: context.mjs now emits AUTONOMY_DIRECTIVE_CHECK as tool-result content in the working turn, telling the model such a claim is a harness default, never session evidence, and to probe once with the question tool before inferring. init.md makes the same test mechanical: tool presence proves an answer mechanism, one real probe round is required, inference afterward must be labeled and disclosed in the first reply. The degraded concept-seed path now also tells the model to disclose the degraded roll instead of presenting it as a full one. Image-gen signaling stays positive-only per Paul: key present emits the capability, absence stays silent so harness-native tools are not suppressed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5575a027dc |
Flag and repair drift in Impeccable's own project artifacts
v4 changed PRODUCT.md's shape and retired the register axis, so an upgraded project can carry answers nothing reads. Nothing measured that. Two tiers, and the split is a performance contract: - Boot (context.mjs, emitting CONTEXT_STALE) spends only what a boot already spends: markdown already in memory, a bounded set of stats, the small JSON files the boot reads anyway. No new directory walks. One directive for the whole set, throttled to once a week per project so a finding the user declined does not reappear tomorrow. - doctor.mjs runs the deep pass on demand: git drift, ignore lists validated against the live rule registry, hook script paths that stop resolving, and the monorepo workspace sweep. --fix applies only the migrations that carry no decision. Findings are data, not prose, so the boot directive, the text report and --json all render one set. Severity says what should happen: auto (fix on the next write anyway), mention (state once), route (name the command that owns the repair). PRODUCT.md now carries a schema stamp so the checks stop reconstructing a file's vintage from which sections it happens to have. Schema version, not release version: a record written by 4.0.0 is not stale under 4.0.1. DESIGN.md gets no stamp, because it follows the external design.md spec that Stitch lints and every DESIGN.md signal is measurable without one. The highest-value catch is a project that resolves to web while carrying native build files, including a monorepo app inheriting a root record that says web. That one costs output quality silently; nothing failed before. doctor follows the hooks/pin pattern rather than the Commands table, so it stays out of the design menu and the count stays at 23. Also corrects CLAUDE.md, which still documented the register axis, reference/brand.md, reference/product.md, eleven deleted domain reference files, and an extractRegister() whose only occurrence in the repo was that sentence. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
6d47843867 |
Stop losing DESIGN.md and native platform refs across init
Bugbot flagged the "resume without rerunning context.mjs" instruction after init. It is right, and the gap is wider than the platform half it named: context.mjs has two output branches, and the no-PRODUCT.md branch omits DESIGN.md, the native platform references, and the unrecognized `## Platform` warning. Because the skill never reruns the script once init writes PRODUCT.md, whatever that first run withheld is gone for the whole session. A greenfield iOS project would be designed without reference/ios.md ever loading, and a project carrying DESIGN.md without PRODUCT.md never saw its own design system. The two halves need different fixes. DESIGN.md is authority in its own right and does not depend on PRODUCT.md existing, so context.mjs now emits it on both branches. Platform is unknowable before PRODUCT.md exists, so no change to the script can recover it; init.md, the one step that learns the answer, now loads ios.md / android.md / both right after recording a native platform, and SKILL.src.md says so where it tells the agent not to rerun. Verified end to end against a temp project on both branches. Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
2b1f36c43e |
Add concept world catalog and review workflow
AI-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. |
||
|
|
2c62f0f4f9 |
de-SaaS the skill: mode-aware rules, neutral runtime injections, diversified examples
Fix batch from the visitor-mode bias audit. The skill's four modes (Persuade / Operate / Read / Experience) now reach the places that were still hard-coded to a SaaS-marketing default: - palette.mjs: rewrote 45 seed blurbs in material/world terms. The 29 tech-tool-world moods (13 Linear-indigo variants, 6 Figma-era, 5 climate-tech, 3 fintech, 2 Glossier DTC, incl. seed-201's docs-page CTA red) lose all company names and product-category words; Aesop trimmed from 17 blurbs to 4 and Klim from 7 to 4, excess rewritten as unnamed material terms. Also carries the earlier bg-block rewrite (brand refs out of the composition doc). - init.md: register explainer now names the four modes and the family each belongs to (stored value stays brand/product for compatibility); Conversion & proof interview + PRODUCT.md section gated to Persuade surfaces only (Experience/Read get no CTA/belief-ladder/proof). - critique.md: Nielsen heuristics 7 and 10 may score n/a on Persuade and Experience surfaces, total renormalized to the applicable max, snapshot records which were n/a; working-memory examples diversified beyond dashboard/pricing anatomy. - Register headers in bolder/delight/quieter/colorize/layout/animate/ typeset renamed from Brand:/Product: to Persuade + Experience: / Operate + Read:; typeset and layout gain one Read-specific sentence (steady reading measure; navigable linearity). - animate.md: plan checklist and implementation order lead with feedback and transitions; the single entrance moment comes after, scoped to modes that invite it. - codex.md: mock inventory says "primary-action treatment (when the surface has one)" instead of assuming a CTA. - delight.md: loading/empty-state/console-egg examples diversified beyond SaaS; streaks/badges scoped to Operate surfaces with recurring tasks. - distill.md: step-removal and next-action lines neutralized away from signup/checkout/CTA vocabulary. - document.md: canonical button label GET STARTED -> SAVE CHANGES; signature components gain a non-marketing example. - antipatterns registry: single-font rule renamed to "Single font without hierarchy" with a description that permits one family when weight/size contrast carries hierarchy. Staged provider copies regenerated via build:skills:release for the touched files only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
51e5af258e |
Expand init to capture positioning, conversion, and proof context (#315)
* Add positioning and conversion questions to init flow Expand init.md so PRODUCT.md captures audience splits, positioning, and brand-register conversion/proof context before design work starts. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix init over-inference by raising the evidence bar for skipping questions. Sparse repos were letting the model treat weak guesses as settled answers; Step 3 now asks unless the codebase provides strong, explicit evidence. Co-authored-by: Cursor <cursoragent@cursor.com> * Improve init interview order and PRODUCT.md proof output shape. Ask positioning in round 1, actively collect proof assets, and give Proof & conversion a plain bullet skeleton so generated PRODUCT.md stays lean. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix init interview bundling and write-time padding, verified via harness runs Co-authored-by: Cursor <cursoragent@cursor.com> * Revert init reference follow-up rule to advisory wording on line 88 Co-authored-by: Cursor <cursoragent@cursor.com> * Tighten init interview rules after harness runs: split register, options, prose Settle split register before brand-only questions, require standalone emotions and confirmed secondary audiences, forbid compound options, and keep PRODUCT.md bold minimal. Co-authored-by: Cursor <cursoragent@cursor.com> * Ask brand-register init questions in magazine-editor voice, no skill jargon Co-authored-by: Cursor <cursoragent@cursor.com> * Fix init chat fallback to ask one question at a time When no structured question tool exists, init should ask in chat with lettered options and wait for each answer instead of dumping a list. Co-authored-by: Cursor <cursoragent@cursor.com> * Resolve init review comments: split purpose question, gate template section Purpose and success are now separate questions, and docs-stated purpose is framed as a hypothesis below the strong-evidence bar rather than a competing always-ask rule. The PRODUCT.md template now tells product register to omit the Conversion & proof section including its heading. Co-authored-by: Cursor <cursoragent@cursor.com> * Keep belief-sequence question out of skill jargon Ask what visitors must believe in plain words; map the answer to the template belief ladder in a parenthetical instead of leading with the term. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Abdul Wahab <abdulwahab@Abduls-MacBook-Pro-2.local> |
||
|
|
3e38e595c7 |
Add platform axis (web / ios / android / adaptive) (#269)
* Add a platform axis (web / ios / android / adaptive) to the skill Orthogonal to register: register decides whether design IS or SERVES the product; platform decides the delivery target and which native conventions apply. Set `## Platform` in PRODUCT.md; a missing field defaults to `web`, so legacy projects are unaffected. - extractPlatform() in skill/scripts/context.mjs (mirrors extractRegister); the CLI appends a NEXT STEP directive to read the native reference(s). `adaptive` (Flutter / RN / KMP shipping both iOS and Android) loads both ios.md and android.md. - New reference/ios.md (Apple HIG distilled) and reference/android.md (Material 3 distilled); reference/web.md is a thin pointer. The native refs frame register's role as narrow: platform conformance is the bar, brand lives in the expressive layer the platform gives you, never by breaking the rails. - Setup step 5 loads the native reference(s) when platform is native. Live mode and the detect CLI stay web-only, gated off ios/android/adaptive. - init asks platform right after register; adapt/audit/animate/layout carry short platform divergence notes; all secondary spots thread `adaptive`. - a11y stays in audit.md (loading it at design time makes output timid), so the native refs carry no Accessibility section; audit.md's Platform section owns native a11y. - Tests: extractPlatform unit coverage + skill-behavior scenario 10 (PRODUCT.md platform ios -> agent loads ios.md). Source-first: only skill/, scripts/, tests/, CLAUDE.md, NOTICE.md, the changelog and version are committed; the sync workflow regenerates the provider trees and ./plugin on merge. ios.md / android.md are distilled from the MIT-licensed ehmo/platform-design-skills; attribution in NOTICE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Address review: gate web tools on native platforms, drop version churn Maintainer-review fixes applied with AI assistance (Claude Code), on top of the rebased platform-axis commit: - Design hook (post-edit and Cursor pre-edit) now resolves the project platform via loadContext + extractPlatform and skips its web rule scan for ios / android / adaptive projects, so React Native / Flutter code never draws web-shaped findings (new hook-lib resolveProjectPlatform / isNativePlatform helpers, covered by unit and subprocess tests). - context.mjs CLI warns on an unrecognized ## Platform value (e.g. a toolchain name like `flutter`) instead of silently defaulting to web; extractRegister / extractPlatform now share extractSectionValue. - Removed reference/web.md: nothing loaded it; CLAUDE.md carries the "web has no extra rulebook" explanation. - init.md: skip live-mode config (Step 6) for native platforms; note the per-app PRODUCT.md pattern for repos shipping web + native. - android.md: Material-everywhere apps that also ship on iPhone still owe iOS OS guarantees (safe areas, Reduce Motion, edge-swipe back). - ios.md: reworded a design-time line that framed Dynamic Type as an accessibility check (a11y stays owned by audit.md). - Renumbered the new skill-behavior scenario to 14 after main's 10-13; updated CLAUDE.md scenario list; added android + unrecognized-value CLI test cases. - No version or changelog changes: versioning happens at release time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Tighten platform reference prose Editorial pass on the platform-axis text, applied with AI assistance (Claude Code) under maintainer direction: - ios.md / android.md rewritten to house style: single-line paragraphs (no hard wraps), one-sentence scope intro, deduplicated intro/slop-test, register-compression down to two sentences. In-file attribution paragraphs removed (NOTICE.md owns attribution); "read on top of the register reference" cruft removed (SKILL step 5 and the context.mjs directive already say it). Bans sections dropped: they restated the rules above them; the two additive items (tab-bar overload, hover-dependent affordances) folded into rules. ~40% smaller each. - Sub-command Platform sections (adapt, audit, animate, layout), SKILL step 5, init.md platform prose, and the context.mjs directive trimmed the same way. Build (prose validators, counts) and both test runners green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Treat an empty PRODUCT.md section as absent, not the next heading Copilot review catch: extractSectionValue read the next `## ...` heading as the section value when a field was left empty, which made the CLI warn "value `## Product Purpose` is not recognized". Stop at the next heading and return null instead. Regression tests for extractPlatform, extractRegister, and the CLI warning path. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Only read a token list of both native targets as adaptive Bugbot catch: after the exact platform tokens failed, any Platform line containing the words ios and android was classified adaptive, so negated or explanatory prose ("web only, not ios or android") silently loaded both native refs and skipped the hook, with no warning. The combo parse now accepts only list separators and the two platform words; anything else falls through to the CLI's unrecognized-value WARNING. Regression tests added. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com> |
||
|
|
da2cda06ed |
Point DESIGN.md spec links at open-source GitHub spec (#299)
* Point DESIGN.md spec links at the open-source GitHub spec. The Stitch docs site is client-rendered and unreliable for agent fetch; the google-labs-code/design.md repo tracks the latest machine-readable spec. Co-authored-by: Cursor <cursoragent@cursor.com> * Sync plugin and harness copies after DESIGN.md spec link update. build:release copies skill/reference into plugin/ and all harness dirs, so refresh those generated outputs here instead of leaving plugin/ stale. Co-authored-by: Cursor <cursoragent@cursor.com> * Use raw GitHub URL for DESIGN.md spec in agent-facing refs. The blob URL serves HTML; raw.githubusercontent.com returns plain markdown that agents can fetch directly. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.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 |