Compare commits
2 Commits
ea992cbc62
...
8536c733ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8536c733ec | ||
|
|
11792ccb33 |
@ -526,3 +526,15 @@ rules:
|
|||||||
- NL trigger keywords ("validate"/"validation") KEPT in the description so "validate my site" still routes here.
|
- NL trigger keywords ("validate"/"validation") KEPT in the description so "validate my site" still routes here.
|
||||||
- **Alternatives rejected**: rename agent + artifacts too (cosmetic symmetry, ~45 extra edits, breaks audit-file family + report back-compat); blind `sed s/validate/web-validate/` (breaks third-party `html-validate`, `validator.nu`, English-verb prose — discrimination must be at the `/validate` token, proven by `.validate-cache/html-validate.json` staying intact).
|
- **Alternatives rejected**: rename agent + artifacts too (cosmetic symmetry, ~45 extra edits, breaks audit-file family + report back-compat); blind `sed s/validate/web-validate/` (breaks third-party `html-validate`, `validator.nu`, English-verb prose — discrimination must be at the `/validate` token, proven by `.validate-cache/html-validate.json` staying intact).
|
||||||
- **Reference**: commit `e5e673a` (18 files). Verified complete: `/validate` = 0 in active code (only `.claude/` history + CHANGELOG), `html-validate` = 15 intact, regex `client-handover-writer.md:1462` shows both names. Linked to [[LRN-045]], [[BDR-031]] (CLAUDE.md routing), [[LRN-043]] (validate routing line).
|
- **Reference**: commit `e5e673a` (18 files). Verified complete: `/validate` = 0 in active code (only `.claude/` history + CHANGELOG), `html-validate` = 15 intact, regex `client-handover-writer.md:1462` shows both names. Linked to [[LRN-045]], [[BDR-031]] (CLAUDE.md routing), [[LRN-043]] (validate routing line).
|
||||||
|
|
||||||
|
## BDR-033 — design-gate §4: anim-lib suggestion — suggest-only, non-blocking, stateless 1-line
|
||||||
|
|
||||||
|
- **Date**: 2026-06-25
|
||||||
|
- **Status**: accepted
|
||||||
|
- **Decision**: `lib/design-gate.md` gains §4. When a non-trivial design task hits a MOTION signal (`animation`/`transition`/`hover`/`motion`/`animate`, added to §DETECTION) AND `detect_anim_eligibility`=`eligible` AND `is_anim_lib_installed` finds none → surface ONE line suggesting the recommended `motion` pkg. Suggest-only (install ONLY on explicit consent, never auto), non-blocking (sole STOP stays §3 exit 10), stateless (ALWAYS the single line, no marker). Calls the helper — no 3rd copy of the lib list.
|
||||||
|
- **Why**: gate runs mid-build; a 2nd blocking stop on an OPTIONAL dep = friction. Dedup goal is not "prevent re-fire" but "make the surface minimal enough that re-fire is never noise" → deterministic by construction (nothing to remember → no fragile behavioral guard, cf [[LRN-046]]/[[LRN-047]]). **Conditional to stakes**: the deduped thing here is a NON-DESTRUCTIVE 1-line cosmetic note → re-fire is annoyance, not risk, so importing marker-grade infra (file + gitignore + permanent state) is not justified. On a DESTRUCTIVE op a deterministic marker IS worth its cost — that is where [[LRN-046]]/[[LRN-047]] were forged. Same determinism bar, opposite cost/benefit; pick by stake. Self-heal: condition-3 (`is_anim_lib_installed`, 10 libs incl gsap/react-spring/lottie) kills it the instant any anim lib lands → re-fire only ever hits "eligible + pure-CSS + actively declined".
|
||||||
|
- **Alternatives rejected**:
|
||||||
|
- File marker `.design-anim-suggested` (once-forever) — "session"→"forever-per-project" (1 decline = permanent silence, no cleanup but manual rm); adds write + gitignore mgmt to a non-mutating doctrine; `.claude/` tracked here → suppression leaks via git.
|
||||||
|
- Blocking yes/skip prompt à la `/onboard` STEP 2.5 — a 2nd STOP mid-build on an optional dep.
|
||||||
|
- Prose "agent remembers not to re-suggest" — fragile behavioral guard, contradicts [[LRN-046]]/[[LRN-047]].
|
||||||
|
- **Reference**: commit `11792cc`, `lib/design-gate.md` §4 + §DETECTION (`+motion`/`+animate`). Helper `lib/animation-lib-check.sh` unchanged. Live via symlink (`~/.claude/lib/`→repo). Builds on [[BDR-005]]. See [[LRN-049]].
|
||||||
|
|||||||
@ -199,3 +199,5 @@ rules:
|
|||||||
- Inspected dirty gstack submodule (parent showed `m`): `package.json`+`bun.lock` = the Playwright 1.58.2→1.61 bump (BDR-029/BLK-008), NOT restore noise → left intact, NOT cleaned, NOT committed (submodule ref stays at clean 070722ace; local patch re-applied by installer by design).
|
- Inspected dirty gstack submodule (parent showed `m`): `package.json`+`bun.lock` = the Playwright 1.58.2→1.61 bump (BDR-029/BLK-008), NOT restore noise → left intact, NOT cleaned, NOT committed (submodule ref stays at clean 070722ace; local patch re-applied by installer by design).
|
||||||
- Renamed skill `/validate` → `/web-validate` (user-surface only): git mv + name + H1 + CLAUDE.md routing + 6 profiles (functional) + cross-refs + agent dispatch + README/USAGE. KEPT: `validator-analyzer` name (lockstep), `.validate-cache`/`VALIDATE.md` (audit-file family), `.claude/` history (append-only), NL triggers. Critical catch: client-deliverable leak-guard regex (`client-handover-writer.md:1462`) matched `/validate` by exact token — `web-` prefix broke the anchored match → extended to `web-validate|validate` (covers legacy docs). Verified complete: `/validate` 0 in active code, `html-validate` 15 intact, regex shows both. Commits e5e673a + dbab542 (BDR-032/LRN-045) + a1cc753 (TODO L167 annotated additively). gstack submodule untouched.
|
- Renamed skill `/validate` → `/web-validate` (user-surface only): git mv + name + H1 + CLAUDE.md routing + 6 profiles (functional) + cross-refs + agent dispatch + README/USAGE. KEPT: `validator-analyzer` name (lockstep), `.validate-cache`/`VALIDATE.md` (audit-file family), `.claude/` history (append-only), NL triggers. Critical catch: client-deliverable leak-guard regex (`client-handover-writer.md:1462`) matched `/validate` by exact token — `web-` prefix broke the anchored match → extended to `web-validate|validate` (covers legacy docs). Verified complete: `/validate` 0 in active code, `html-validate` 15 intact, regex shows both. Commits e5e673a + dbab542 (BDR-032/LRN-045) + a1cc753 (TODO L167 annotated additively). gstack submodule untouched.
|
||||||
- TDD'd `/prune-memory` (only destructive skill, untested + carried a false `Fixed in v1.1 (TDD found it)` claim): 6 dangers (RED-1..6) closed by deterministic guards, skill `0a3e766`. Real-data run on learnings.md exposed SAFE≠USEFUL (compression marginal on dense; value = index/merge, not C) + a 13/13-false-positive line-grep fidelity guard → replaced by a per-entry count census (0 FP, proven counting both sides). RED-7 (example-priming) + RED-8 (added-negation) filed in BACKLOG. EVAL-006, LRN-046/047/048.
|
- TDD'd `/prune-memory` (only destructive skill, untested + carried a false `Fixed in v1.1 (TDD found it)` claim): 6 dangers (RED-1..6) closed by deterministic guards, skill `0a3e766`. Real-data run on learnings.md exposed SAFE≠USEFUL (compression marginal on dense; value = index/merge, not C) + a 13/13-false-positive line-grep fidelity guard → replaced by a per-entry count census (0 FP, proven counting both sides). RED-7 (example-priming) + RED-8 (added-negation) filed in BACKLOG. EVAL-006, LRN-046/047/048.
|
||||||
|
- Wired `design-gate.md` §4: anim-lib suggestion when a design task hits a motion signal — suggest-only, non-blocking, stateless 1-line (no marker). `motion`/`animate` added to §DETECTION (source). Chose stateless-minimal over a state marker, conditional on stakes: a 1-line cosmetic note's re-fire is annoyance not risk → no marker-grade infra (unlike LRN-046/047's destructive context). Helper unchanged, no 3rd copy of the lib list. Live via symlink. BDR-033, LRN-049.
|
||||||
|
- Process: caught "write-before-show" twice this session on a live (symlinked) file → on edit=deploy targets the pre-write diff is the only control gate → inverted to show→validate→write. LRN-050.
|
||||||
|
|||||||
@ -627,3 +627,19 @@ rules:
|
|||||||
- **Context**: prune-memory v1.1 (EVAL-006). v1 STEP-4 verify always reported OK (wrong prefix → 0 markers → blank). The fix's 0-false-positive is only trustworthy because the census was shown counting both sides.
|
- **Context**: prune-memory v1.1 (EVAL-006). v1 STEP-4 verify always reported OK (wrong prefix → 0 markers → blank). The fix's 0-false-positive is only trustworthy because the census was shown counting both sides.
|
||||||
- **Future application**: any verify/test/lint reporting success — design the pass to surface what it examined (counts / files / lines) so a vacuous pass is visible, not silent.
|
- **Future application**: any verify/test/lint reporting success — design the pass to surface what it examined (counts / files / lines) so a vacuous pass is visible, not silent.
|
||||||
- **Reference**: skill `0a3e766`, EVAL-006 (verify-proof anomaly). Linked to [[EVAL-006]].
|
- **Reference**: skill `0a3e766`, EVAL-006 (verify-proof anomaly). Linked to [[EVAL-006]].
|
||||||
|
|
||||||
|
## LRN-049 — Non-destructive repeated nudge: stateless-minimal surface > state marker (conditional on stakes)
|
||||||
|
|
||||||
|
- **Date**: 2026-06-25
|
||||||
|
- **Pattern**: To dedup a REPEATED but NON-DESTRUCTIVE suggestion (hint/nudge/advisory in a stateless flow — gate, hook, lint note), minimize the surface (always 1 line) instead of a persistence marker. A marker buys "exactly once" but costs state (file + gitignore + location), wrong scope ("session" via a plain file = forever-per-project), and staleness with no cleanup. Goal is not "prevent re-fire" but "make re-fire cheap enough to never be noise" — strip the per-occurrence richness and there is nothing left to dedup. **Conditional on stakes**: [[LRN-046]]/[[LRN-047]] ("deterministic > behavioral", "noisy guard = risk") were forged on a DESTRUCTIVE skill where a false-green = data loss → there a deterministic marker earns its cost. Here it is a 1-line cosmetic note → re-fire is annoyance, not risk → do NOT import marker-grade infra. Same determinism requirement, opposite cost/benefit.
|
||||||
|
- **Context**: design-gate §4 anim-lib suggestion ([[BDR-033]]). User reserved the marker-vs-refire call; winning third option was "always 1 line, stateless".
|
||||||
|
- **Future application**: any repeated advisory in a stateless surface — first bound the noise by minimizing the surface; reach for a marker/flag-file ONLY when a missed dedup is costly (destructive, irreversible, money, security), not merely repetitive. Match the guard's cost to the stake it protects.
|
||||||
|
- **Reference**: `lib/design-gate.md` §4, [[BDR-033]]. Conditions [[LRN-046]], [[LRN-047]].
|
||||||
|
|
||||||
|
## LRN-050 — On a symlinked/live file, show-before-write is the ONLY control gate
|
||||||
|
|
||||||
|
- **Date**: 2026-06-25
|
||||||
|
- **Pattern**: When the edit target is symlinked into the live path (`~/.claude/lib/`→repo, `~/.claude/CLAUDE.md`→repo …), saving the file IS deploying it — write and go-live collapse into one act. No later deploy step catches a bad change, so the pre-write review (show the drafted diff, get explicit go) is the ONLY checkpoint before the change is in service — unlike a normal file where build/commit/deploy offers a second net. On live/symlinked targets, show→validate→write is mandatory, not courtesy; "edit silently then show" forfeits the only gate.
|
||||||
|
- **Context**: this session twice wrote-then-showed on `lib/design-gate.md` (live via symlink). Both harmless (non-destructive), but the pattern would bite on a destructive live edit. User flagged it → inverted to show→validate→write.
|
||||||
|
- **Future application**: before editing any file, check if it is live (`readlink -f`, compare to `~/.claude/`); if live, treat the pre-write diff as a mandatory approval gate, not an optional preview. Generalizes to any "edit = deploy" target (dotfiles, served config, hot-reloaded sources).
|
||||||
|
- **Reference**: `lib/design-gate.md` (symlink → `~/.claude/lib/`). Sibling to [[LRN-044]] (write-through-symlink → resolve real path). Linked to [[BDR-033]].
|
||||||
|
|||||||
@ -12,7 +12,7 @@ Check BOTH the task description AND the filesystem:
|
|||||||
|
|
||||||
**Task description signals** (case-insensitive match on $ARGUMENTS):
|
**Task description signals** (case-insensitive match on $ARGUMENTS):
|
||||||
- UI keywords: `component`, `button`, `card`, `modal`, `dialog`, `tooltip`, `dropdown`, `sidebar`, `navbar`, `header`, `footer`, `layout`, `grid`, `form`, `input`, `table`
|
- UI keywords: `component`, `button`, `card`, `modal`, `dialog`, `tooltip`, `dropdown`, `sidebar`, `navbar`, `header`, `footer`, `layout`, `grid`, `form`, `input`, `table`
|
||||||
- Style keywords: `css`, `style`, `theme`, `color`, `font`, `spacing`, `margin`, `padding`, `border`, `shadow`, `animation`, `transition`, `hover`, `responsive`, `dark mode`, `light mode`
|
- Style keywords: `css`, `style`, `theme`, `color`, `font`, `spacing`, `margin`, `padding`, `border`, `shadow`, `animation`, `transition`, `hover`, `motion`, `animate`, `responsive`, `dark mode`, `light mode`
|
||||||
- Design keywords: `design`, `ui`, `ux`, `visual`, `polish`, `pixel`, `figma`, `mockup`, `wireframe`, `prototype`
|
- Design keywords: `design`, `ui`, `ux`, `visual`, `polish`, `pixel`, `figma`, `mockup`, `wireframe`, `prototype`
|
||||||
- Framework UI: `tailwind`, `styled-component`, `emotion`, `chakra`, `radix`, `shadcn`, `headless`
|
- Framework UI: `tailwind`, `styled-component`, `emotion`, `chakra`, `radix`, `shadcn`, `headless`
|
||||||
|
|
||||||
@ -83,6 +83,61 @@ Exit codes: `0` = ready · `11` = ready-but-unverified (proceed, but surface it)
|
|||||||
having them confirm with `claude mcp list` / `claude plugin list`. Fail-visible,
|
having them confirm with `claude mcp list` / `claude plugin list`. Fail-visible,
|
||||||
not fail-silent — the most important tool (magic) is exactly an unverifiable one.
|
not fail-silent — the most important tool (magic) is exactly an unverifiable one.
|
||||||
|
|
||||||
|
### 4. Animation library — suggest-only (fires only on a real motion signal)
|
||||||
|
|
||||||
|
Orthogonal to the toolchain check above: §2-3 are about Claude's design TOOLS;
|
||||||
|
this is about the PROJECT's runtime dep. Evaluate it only once the toolchain is
|
||||||
|
resolved and you're actually proceeding with the build (READY, or after the user
|
||||||
|
ran `/profile design`). Never on the INCOMPLETE stop path — that path has one
|
||||||
|
action only (`/profile design`); don't stack an optional note on it.
|
||||||
|
|
||||||
|
**Fires only when ALL THREE hold** — drop any one → no suggestion, stay silent:
|
||||||
|
|
||||||
|
1. **Motion signal** — the task matched a motion keyword from §DETECTION:
|
||||||
|
`animation`, `transition`, `hover`, `motion`, or `animate`. A static
|
||||||
|
button / card / layout with no motion signal needs no anim lib → skip.
|
||||||
|
2. **Stack eligible** — `detect_anim_eligibility` returns `eligible|…`.
|
||||||
|
3. **No anim lib yet** — `is_anim_lib_installed` finds none.
|
||||||
|
|
||||||
|
Only if condition 1 holds, run the helper for 2 and 3 — do NOT re-list packages
|
||||||
|
here; the helper's `is_anim_lib_installed` is the single source of which libs
|
||||||
|
count:
|
||||||
|
|
||||||
|
source "$HOME/.claude/lib/animation-lib-check.sh"
|
||||||
|
result=$(detect_anim_eligibility) # '<status>|<package>|<reason>'
|
||||||
|
status=$(echo "$result" | cut -d'|' -f1)
|
||||||
|
pkg=$(echo "$result" | cut -d'|' -f2)
|
||||||
|
reason=$(echo "$result" | cut -d'|' -f3)
|
||||||
|
if [ "$status" = "eligible" ] && ! is_anim_lib_installed >/dev/null; then
|
||||||
|
cmd=$(recommend_anim_install_cmd "$pkg") # pnpm/yarn/bun/npm per lockfile
|
||||||
|
# → surface the one-line suggestion below. Do NOT run $cmd.
|
||||||
|
fi
|
||||||
|
|
||||||
|
**Surface — always this single line (non-blocking, suggest-only):**
|
||||||
|
|
||||||
|
🎬 Stack motion-eligible (<reason>), no anim lib — `<cmd>`? (optional; say the word, I'll add it)
|
||||||
|
|
||||||
|
**Rules:**
|
||||||
|
|
||||||
|
- **Suggest-only, never auto-install.** Run `<cmd>` ONLY on explicit user
|
||||||
|
consent. BDR-005: mid-session + existing `package.json` = consent required —
|
||||||
|
same contract as `/onboard` STEP 2.5, opposite of `/init-project` STEP 5e
|
||||||
|
(auto-install on a just-validated fresh scaffold).
|
||||||
|
- **Non-blocking.** Never halts the build; NOT a second gate. The toolchain stop
|
||||||
|
(§3, exit 10) is the only STOP. Surface the line, keep going.
|
||||||
|
- **Stateless dedup, by construction.** The suggestion is ALWAYS the single line
|
||||||
|
above — no first-time-block / later-short split. That split would need session
|
||||||
|
state the gate doesn't have, and a file marker would persist forever (per
|
||||||
|
project, not per session). Determinism here comes from having nothing to
|
||||||
|
remember, not from a behavioral "the agent recalls it" guard. Re-fire is one
|
||||||
|
ignorable line, on a narrow population: condition 3 (`is_anim_lib_installed`,
|
||||||
|
10 libs incl gsap / react-spring / lottie) kills it the instant any anim lib
|
||||||
|
lands, so only "eligible + pure-CSS + actively declined" ever sees it twice.
|
||||||
|
- **Two "motion"s (agent-facing).** The lib `motion` (npm dep, this step) ≠ the
|
||||||
|
skill `design-motion-principles` (`# GATE-BLOCK:` core set, §2-3). The
|
||||||
|
toolchain check handles the skill; this step handles the lib. Don't conflate
|
||||||
|
them when talking to the user.
|
||||||
|
|
||||||
### Other toolchains
|
### Other toolchains
|
||||||
|
|
||||||
The script defaults to the `design` profile. A task needing another profile's
|
The script defaults to the `design` profile. A task needing another profile's
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user