forked from bchanot/claude
chore(memory): case 7 registries, contracts, CHANGELOG — BDR-104 LRN-174 EVAL-033
This commit is contained in:
@@ -125,6 +125,7 @@ rules:
|
||||
| BDR-101 | 2026-09-25 | `full` = default profile: no selection ⇒ full in force, `reset` applies it, install applies it | accepted |
|
||||
| BDR-102 | 2026-09-27 | agent-skills: no plugin, vendor 3 skills + build floor-guard + routing census + rest-api rule | accepted |
|
||||
| BDR-103 | 2026-09-27 | 6-repo review: 5 verdicts, 3 criteria (grep-verified coverage, per-session cost, doctrine conflict); stars decided nothing | accepted |
|
||||
| BDR-104 | 2026-09-28 | MengTo motion pack: vendor 5 scroll skills pinned via shared lib/vendor-skills.sh + build personal skill site-motion; 17 skipped | accepted |
|
||||
|
||||
---
|
||||
|
||||
@@ -1297,3 +1298,12 @@ Branch feature/user-writing-web-rules, UNMERGED (human gate).
|
||||
- **Alternatives rejected**: install-then-prune (sunk cost, [[BDR-047]] ECC lesson); one bulk verdict (user wanted one case per turn, each with a build-vs-install call); building reticle's engine (1 286 server files).
|
||||
- **Caveats**: borrowed prompts change upstream with no diff, the pin is the review point; do not re-audit these six expecting more; mengto motion pack from the ui-skills registry is the open follow-up if site-level choreography (GSAP/ScrollTrigger, WebGL hero, masked reveals) proves thin locally.
|
||||
- **Reference**: branches feature/yagni-ladder (9315c6c, de7371d), feature/agent-skills-borrow (d28c45e 2b25cb4 409db51 1a8e6de 7401383 6617889 d71f3a7), feature/web-building-microrules (a2e654d 5a27372), chore/six-repo-review-notes (da35cde 197225a). Links [[BDR-102]] [[LRN-172]] [[LRN-173]] [[EVAL-032]] [[BDR-047]] [[BDR-006]].
|
||||
|
||||
## BDR-104 — MengTo motion pack: vendor 5 scroll skills via a shared helper + build `site-motion`; 17 skipped
|
||||
- **Date**: 2026-09-28
|
||||
- **Status**: accepted, feature/mengto-site-motion, UNMERGED (human gate)
|
||||
- **Decision**: (1) `lib/vendor-skills.sh` = one `vendor_pinned_skills <lock-key> [refresh]` for every curl-vendored upstream (agent-skills moved onto it; lock `skills` as list or dict of file lists; python argv lock read; `..`/charset guard; `VENDOR_BASE_URL` only as `file://`; tmp+mv; refresh skips never-installed skills, update-all convention). (2) Vendored at a965851: scroll-world-storytelling, build-threejs-scroll-worlds (+5 refs incl. scroll-conductor.js), scroll-scrubbed-visual-sequence, scroll-scrubbed-word-reveal, scroll-progress-timeline; text only, never demo/agents/binaries; design/web/web-full/full profiles. (3) `skills/site-motion` personal: invariants of the other 17 (gates, engine choice, Lenis sync, Astro ClientRouter lifecycle, numbered recipes, pitfalls); routed in CLAUDE.global.md Build UI chain + design-gate (not GATE-BLOCK).
|
||||
- **Why**: user asked whether the UI profiles carry motion knowledge for lively sites. Census: component polish deep (emil 27 KB, motion cookbook, impeccable animate), site choreography thin as workflows; ui-ux-pro-max CSVs cover terms but as search rows ([[LRN-174]]). Two analyzers read 22 skills: 5 clean workflows/recipes absent locally; 17 covered, generic, buggy (reduced-motion `clearProps`, gate before `registerPlugin`, no-JS opacity 0, refresh-rate `phi`) or Codex/Xcode machinery → distil per [[LRN-141]]. Registry sample (11) ≠ catalog (88): always list the tree.
|
||||
- **Alternatives rejected**: vendor all 22 (bugs + duplicates + 17×~100 tok descriptions); distil only (loses the two deep workflows whose value is their full text); second inline curl loop (duplication; helper instead); `VENDOR_BASE_URL` gated by a companion var (file:// prefix check suffices); grouped toggle pack (per-name like emil).
|
||||
- **Caveats**: vendored prompts change upstream with no diff, pin = review point; GSAP-first content vs [[BDR-005]] `motion` default, site-motion states the allowance; LOW hardening open: `re.match` `$` accepts a trailing newline, `source`/`path`/`sha` lock fields not charset-checked; `make link` + `bash lib/profile.sh apply full` after merge (user); sub-agent leftovers `/tmp/mengto-verify` (user removes).
|
||||
- **Reference**: commits 2a1ad17 (helper + vendoring), ba14b5e (site-motion); contracts `.claude/tasks/contracts/2026-09-27-{mengto-vendor,site-motion-skill}-0002.md`; gates MET, verifiers CONFORME after 3 re-dispatches (frontmatter shape, refresh convention, security env override + traversal), security PASS ×2, `make test` 36 suites green minus 2 pre-existing T16a. Links [[BDR-103]] [[BDR-102]] [[LRN-141]] [[LRN-174]] [[EVAL-033]].
|
||||
|
||||
@@ -53,6 +53,7 @@ rules:
|
||||
| EVAL-030 | 2026-09-24 | 2026-09-24 self-audit: two regressions and one guardrail bypass came from my own process, not from the tools | BDR-100 mechanisms shipped; re-run census at next doctrine wave |
|
||||
| EVAL-031 | 2026-09-25 | /feat run for BDR-101: challenge round earned its cost, two blockers sat in my own premises | keep challenge round on state-detection plans; check live state before planning; pin grep in oracles |
|
||||
| EVAL-032 | 2026-09-27 | 4 parallel feater executors, one tree, gate loop: verifier caught a vacuous test, security caught a partial-write; my oracles wrong twice | keep same-tree parallel dispatch with disjoint FILE SCOPE + orchestrator-owned shared files; blind verifier stays; measure oracles on precedents |
|
||||
| EVAL-033 | 2026-09-28 | case 7: 2 analyzers + 2 executors + 3 re-dispatches; verifiers caught shape, convention and my wrong count; security caught an env override | brief names the scratchpad path explicitly (3 /tmp leftovers); keep blind verifiers; count claims get an artifact |
|
||||
|
||||
---
|
||||
|
||||
@@ -314,3 +315,10 @@ Dogfood: 3 blind lenses attacked the v1 plan for the plan-challenge feature itse
|
||||
- **Result**: 4/4 CONFORME after 2 re-dispatches; security PASS ×2. Verifier A3 caught a vacuous distinct-pair test the executor had self-justified ([[LRN-172]]). Security caught first-download without tmp+mv (partial file accepted forever) + python source splicing → fixed by fresh executor, re-verified, re-audited. Executors never touched each other's files; A4 verifier counted the orchestrator-reserved CHANGELOG as ECARTS(1), correct by contract wording.
|
||||
- **Anomalies**: (1) my oracles wrong twice ([[LRN-173]]); (2) gates.sh ERROR(3) on first run, `EVIDENCE: pending` missing; (3) 3 guardrail denials on sub-agents (`export GIT_CONFIG_GLOBAL` inline ×2 incl. a verifier, `rm -rf /tmp/tmp.AAyJzvufO6` executor cleanup), all reported, none evaded — [[BDR-100]] live; (4) security-auditor miscounted the sha as 41 chars (it is 40) — verify sub-agent claims before acting; (5) `make test` rc 1 from the 2 pre-existing T16a, my first grep filter hid the totals.
|
||||
- **Action**: keep the pattern; add `EVIDENCE: pending` to the contract skeleton; floor-guard waiver policy → user decision; snippet framing for LLM-consumed output → follow-up.
|
||||
|
||||
## EVAL-033 — case 7 execution: analyzers first, then two executors, three re-dispatches
|
||||
- **Date**: 2026-09-28
|
||||
- **Method**: two read-only analyzers (22 skills, fixed per-skill format, grep overlap against local assets) → verdict → two contracts → two feater executors in parallel (disjoint scopes, profiles owned by one, CHANGELOG by me) → gates.sh → fresh verifiers → security ×2 → full `make test`.
|
||||
- **Result**: both CONFORME after 3 re-dispatches: frontmatter shape (executor mirrored external peers instead of the named personal ones), update-all refresh convention (executor's "additive" install broke "not installed — skipping"), security MEDIUM env override + LOW traversal. Verifier also doubted my CHANGELOG "sixteen skipped" → it was seventeen. Byte-for-byte fidelity of 14 files confirmed twice.
|
||||
- **Anomalies**: (1) three sub-agents wrote to `/tmp` outside the scratchpad then could not `rm -rf` (refused, correctly) — the brief must name the scratchpad path; (2) executors' self-justified deviations were plausible each time and wrong twice → blind verifier stays mandatory; (3) analyzer reports at ~120-180 words per skill were the right grain, two of them fit my context; (4) `make test` rc 1 is still the 2 pre-existing T16a, my filter now shows totals.
|
||||
- **Action**: brief template line "scratch only under <scratchpad>"; count claims in CHANGELOG/journal cite the list they count; keep the analyzer-first pattern for any pack > 5 skills.
|
||||
|
||||
@@ -528,3 +528,6 @@ rules:
|
||||
- User go "merge le tout": the four review branches merged into develop via `gitflow finish` → b3597eb (yagni-ladder), 04cb057 (agent-skills-borrow), 68fcdaf (web-building-microrules), 39d5b15 (six-repo-review-notes); 7 registry conflicts (TODO ×3, journal ×3, CHANGELOG, decisions ×2) resolved by a scratch resolver keeping both sides in order (TODO/CHANGELOG incoming first, registries HEAD first), merge commits by hand, finish re-run removed local + origin copies. develop == origin/develop, no review branch left. Post-merge: 0 conflict markers, BDR-101→103 in order, `make test` 35 suites green minus 2 pre-existing T16a, shellcheck clean. BDR-103 written on user go. Open for the user: `make link` + `bash lib/profile.sh apply full` (trio symlinks), `rm -rf /tmp/tmp.AAyJzvufO6`.
|
||||
- User asked whether the UI profiles already carry motion-design knowledge for lively modern sites. Census answer: micro-interaction + component polish deep (emil 27 KB, motion cookbook 14 sections incl. scroll-driven, impeccable animate + detect); site-level choreography thin (GSAP/ScrollTrigger storytelling, Lenis, WebGL hero, masked reveals, marquee as workflows) and Astro View Transitions at zero mentions despite Astro-first. Candidate: mengto motion pack from the ui-skills registry, same three criteria; user decides.
|
||||
- Correction to the motion census above: ui-ux-pro-max's data CSVs (motion.csv 17 rows: GSAP reveal/pin/scrub, SplitText, parallax, magnetic; stacks/threejs.csv 53 rows; stacks/astro.csv rows 28-31 ViewTransitions: ClientRouter, `transition:name`, no-JS fallback; landing.csv scrollytelling) cover what I called absent. My grep skipped the plugin's data files. They are search-DB rows reached through the skill's search tool, not build workflows. Case 7 (mengto pack, 22 skills read by two analyzers): verdict pending user decision.
|
||||
|
||||
## 2026-09-28
|
||||
- Case 7 (MengTo motion pack), user go "l'hybride" → [[BDR-104]]: `lib/vendor-skills.sh` shared helper (agent-skills moved onto it), 5 scroll skills vendored at a965851 (2a1ad17), `skills/site-motion` personal skill + routing (ba14b5e). Two analyzers read 22 skills first; 17 skipped (bugs, duplicates, covered, Codex/Xcode machinery). Gates MET, verifiers CONFORME after 3 re-dispatches (frontmatter shape, update-all refresh convention, security env override + traversal), security PASS ×2, `make test` 36 suites green minus 2 pre-existing T16a, shellcheck clean. [[LRN-174]] [[EVAL-033]]. feature/mengto-site-motion UNMERGED. Open for the user: `make link` + `bash lib/profile.sh apply full`, `rm -rf /tmp/mengto-verify`, LOW hardening (regex trailing newline, source/path/sha charset).
|
||||
|
||||
@@ -193,6 +193,7 @@ rules:
|
||||
| LRN-171 | 2026-09-25 | sub-agent sandbox: grep shim returns EMPTY inside `$(...)` for patterns holding literal `$VAR` — oracles pin `command grep` | contract CHECK lines, hermetic test greps, hooks parsing grep output |
|
||||
| LRN-172 | 2026-09-27 | TF-IDF cosine on a 2-doc corpus is identically 0: similarity self-tests need N ≥ 4, a same-corpus positive control and a sensitivity re-run | fixtures for any corpus-normalised statistic (idf, z-score, ranking), "distinct pair passes" tests |
|
||||
| LRN-173 | 2026-09-27 | contract oracles written from memory failed twice: run the CHECK on the precedent files first, census greps via `git grep` (tracked only), `EVIDENCE: pending` mandatory for gates.sh | contract CHECK lines, precedent-mirroring criteria, gates.sh ledgers |
|
||||
| LRN-174 | 2026-09-28 | a coverage census must grep plugin DATA files (CSV/JSON search DBs), not only SKILL.md prose; and a registry sample is not the upstream catalog, list the tree | before claiming a gap in installed skills; before scoping an external-repo evaluation |
|
||||
|
||||
---
|
||||
|
||||
@@ -1615,3 +1616,7 @@ Rule: when editing a doctrine file under structure locks, grep the test's lock s
|
||||
## LRN-173 — contract oracles written from memory failed twice: run the CHECK on the precedent files first, census greps via `git grep`, `EVIDENCE: pending` mandatory
|
||||
- **Context**: same run, two orchestrator oracle bugs. (1) "≤ 80 chars" over the whole file: rules/web-building.md line 2 (`paths:` frontmatter) is already 110 chars, so the criterion contradicted the precedent it named; executor returned NEED-DECISION instead of bending. (2) emil-citers census with `grep -rl` hit gitignored `install-*.log` at the repo root; `git grep -l` (tracked only) is the right census tool. (3) gates.sh `run` errors `runnable but has no EVIDENCE: line` unless each criterion carries `EVIDENCE: pending`.
|
||||
- **Apply**: before shipping a CHECK, run it against the files it claims to mirror; census oracles = `git grep`; contract skeleton carries `EVIDENCE: pending` per criterion (check /feat's template writes it). Oracle fixes are orchestrator-owned, never a re-dispatch ([[BDR-102]]).
|
||||
|
||||
## LRN-174 — a coverage census greps plugin data files too; a registry sample is not the catalog
|
||||
- **Context**: I told the user Astro View Transitions had zero local mentions. ui-ux-pro-max's `data/stacks/astro.csv` rows 28-31 carry ClientRouter, `transition:name`, no-JS fallback; `motion.csv` carries GSAP pin/scrub, SplitText, parallax. My grep covered SKILL.md prose and archetypes, not the plugin's CSV search DB. Same day: the ui-skills registry showed 11 MengTo skills; the repo tree has 88 web-design skills, and the substantive ones were outside the sample.
|
||||
- **Apply**: census = `grep -rl` over the plugin cache including data dirs, then say "row in a search DB" vs "workflow"; evaluating an upstream = `git/trees?recursive=1` first, sample never. Correct the user the moment the miss is found ([[BDR-104]]).
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# TODO
|
||||
|
||||
## 2026-09-27 — case 7: MengTo motion pack → vendor 5 + build site-motion (feature/mengto-site-motion)
|
||||
User go "ok pour 1, l'hybride" after two analyzers read 22 skills. Contracts under
|
||||
`.claude/tasks/contracts/2026-09-27-{mengto-vendor,site-motion-skill}-*`, two feater
|
||||
executors in parallel, gates replayed (gates.sh → fresh verifier → security).
|
||||
- [x] M1 2a1ad17 vendor scroll-world-storytelling, build-threejs-scroll-worlds (+5 refs),
|
||||
scroll-scrubbed-visual-sequence, scroll-scrubbed-word-reveal,
|
||||
scroll-progress-timeline at pinned a965851 via a shared `lib/vendor-skills.sh`
|
||||
(agent-skills moves onto it), design profiles, hermetic suite.
|
||||
- [x] M2 ba14b5e `skills/site-motion/SKILL.md` + test-prompts.json: distilled invariants
|
||||
(gates, engine choice, Lenis sync, Astro ClientRouter lifecycle, numbered
|
||||
recipes, upstream pitfalls), routing line in CLAUDE.global.md + design-gate.
|
||||
- [x] M3 gates MET ×2, verifiers CONFORME ×2 after 3 re-dispatches, security PASS ×2,
|
||||
make test 36 suites green minus 2 pre-existing T16a, CHANGELOG, BDR-104 LRN-174
|
||||
EVAL-033. UNMERGED — human gate. After merge: `make link` + `bash lib/profile.sh
|
||||
apply full`; user removes `/tmp/mengto-verify`.
|
||||
Follow-up LOW (security): `SAFE` regex `$` accepts a trailing newline (use `\Z`);
|
||||
`source`/`path`/`commit` lock fields not charset-checked in lib/vendor-skills.sh.
|
||||
Skipped on purpose (analysis 2026-09-27): cinematic-gsap-lenis (reduced-motion bug),
|
||||
cinematic-scroll-storytelling (50 % duplicate), build-awwwards-quality-sites (0 code),
|
||||
animation-systems, gsap, threejs (⊂ ui-ux-pro-max threejs.csv), cobejs, matterjs,
|
||||
marquee-loop, masked-reveal (gate bug), animation-on-scroll (no-JS bug),
|
||||
progressive-blur, webgl-landing-steering, staggered-word-reveal (covered),
|
||||
gsap-scrolltrigger-storytelling (empty), optimize-web-animations (Codex machinery),
|
||||
performance-profiling (Xcode). Their invariants live in site-motion.
|
||||
|
||||
## 2026-09-27 — case 5 of the 6-repo review: OmniRoute rejected (chore/six-repo-review-notes)
|
||||
Gateway to 357 providers via `ANTHROPIC_BASE_URL` → localhost:20128; needs provider
|
||||
API keys, a Claude Pro/Max subscription cannot go through it. No gap here: Claude-only
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# CONTRACT — mengto-vendor
|
||||
- date: 2026-09-27 | flow: feat (ad-hoc dispatch, /feat gates replayed by the orchestrator) | branch: feature/mengto-site-motion
|
||||
- status: active
|
||||
|
||||
## REQUEST (verbatim — IMMUTABLE)
|
||||
> Vendor five scroll-choreography skills from MengTo/Skills (`agent-skills/web-design`) as machine-owned copies at pinned commit `a965851e27dc179e693fde1bee94457a64e1a7a5` (main, 2026-09-23), text files only: scroll-world-storytelling (SKILL.md, REFERENCES.md); build-threejs-scroll-worlds (SKILL.md, references/kage-anatomy.md, references/quality-and-qa.md, references/realtime-architecture.md, references/scroll-conductor.js, references/world-bible.md); scroll-scrubbed-visual-sequence (SKILL.md, REFERENCES.md); scroll-scrubbed-word-reveal (SKILL.md, REFERENCES.md); scroll-progress-timeline (SKILL.md, REFERENCES.md). Never demo/, agents/, assets, images, video, fonts or minified js. Lock entry `mengto-skills` with per-skill file lists; install and update read the pin from the lock; the vendoring loop becomes ONE shared helper used by both the agent-skills entry and this one (agent-skills behaviour unchanged, re-verified). Registered like emil-design-eng in link.sh, .gitignore, lib/toggle-external.sh, lib/profile.sh MANAGED_EXTERNALS and the design-class profiles (design, web, web-full, full). User go 2026-09-27 ("ok pour 1, l'hybride", case 7 of the repo review).
|
||||
|
||||
## CLARIFICATIONS
|
||||
- Lock shape: `"mengto-skills": {"source": "https://github.com/MengTo/Skills", "commit": "<sha>", "path": "agent-skills/web-design", "skills": {"<name>": ["SKILL.md", "..."]}, "managed_by": "curl", "note": "..."}`. The helper accepts both shapes: `skills` as a list of names (agent-skills: files = ["SKILL.md"], path default "skills") and as a dict name → file list.
|
||||
- Helper: `lib/vendor-skills.sh`, function `vendor_pinned_skills <lock-key> [refresh]`, sourced by install-plugins.sh (Step 8e, replacing its inline loop) and update-all.sh (step 7.3, replacing its inline loop). Reads the lock with python3 via argv (never string-spliced). Raw URL = `https://raw.githubusercontent.com/<owner>/<repo>/<sha>/<path>/<name>/<file>`; the prefix up to `<sha>` is overridable through `VENDOR_BASE_URL` so a hermetic test can serve `file://` fixtures. Per file: tmp + mv, tmp removed on failure; a skill counts as installed only when every listed file landed, otherwise `err` with the manual curl. Skip files already present unless `refresh`. Subdirectories (references/) created as needed.
|
||||
- Byte-for-byte copies; Codex-isms in the text stay.
|
||||
- Profiles: the five under the design/external section of design, web, web-full, full; ALSO add the line `site-motion` with the `personal` label to the same four profiles (a sibling contract writes skills/site-motion and must not touch profiles); mirror how personal design skills are listed there. Never backend/dev.
|
||||
- Not mirrored on purpose (design-only or sibling-owned): CLAUDE.global.md, lib/design-gate.md, agents/plugin-advisor.md, agents/plugin-probe.md, lib/tests/fixtures/registry-index-drift.md, lib/profiles/backend.profile, lib/profiles/dev.profile.
|
||||
- Executor materializes the files with the same curl (network read allowed); never runs link.sh, make link, make plugin, update-all.sh or install-plugins.sh.
|
||||
- Routing census pre-checked 2026-09-27: no pair ≥ 0.50 among the five descriptions.
|
||||
|
||||
## ACCEPTANCE CRITERIA
|
||||
1. Every listed file present per skill, frontmatter name = dir name, nothing else vendored.
|
||||
CHECK: ok=1; declare -A F=( [scroll-world-storytelling]="SKILL.md REFERENCES.md" [build-threejs-scroll-worlds]="SKILL.md references/kage-anatomy.md references/quality-and-qa.md references/realtime-architecture.md references/scroll-conductor.js references/world-bible.md" [scroll-scrubbed-visual-sequence]="SKILL.md REFERENCES.md" [scroll-scrubbed-word-reveal]="SKILL.md REFERENCES.md" [scroll-progress-timeline]="SKILL.md REFERENCES.md" ); for s in "${!F[@]}"; do for f in ${F[$s]}; do [ -f "skills-external/$s/$f" ] || { echo "missing $s/$f"; ok=0; }; done; grep -q "^name: $s\$" "skills-external/$s/SKILL.md" || { echo "name mismatch $s"; ok=0; }; n=$(find "skills-external/$s" -type f | wc -l); [ "$n" -eq "$(echo ${F[$s]} | wc -w)" ] || { echo "extra files in $s"; ok=0; }; done; [ "$ok" -eq 1 ] && echo VENDORED
|
||||
EXPECT: VENDORED
|
||||
EVIDENCE: MET exit=0 marker-found :: VENDORED
|
||||
2. Pin and file lists recorded in the lock.
|
||||
CHECK: python3 -c 'import json; d=json.load(open("plugins.lock.json"))["mengto-skills"]; assert d["commit"]=="a965851e27dc179e693fde1bee94457a64e1a7a5", d; assert d["path"]=="agent-skills/web-design"; s=d["skills"]; assert set(s)=={"scroll-world-storytelling","build-threejs-scroll-worlds","scroll-scrubbed-visual-sequence","scroll-scrubbed-word-reveal","scroll-progress-timeline"}, s; assert set(s["build-threejs-scroll-worlds"])=={"SKILL.md","references/kage-anatomy.md","references/quality-and-qa.md","references/realtime-architecture.md","references/scroll-conductor.js","references/world-bible.md"}; assert all(set(v)=={"SKILL.md","REFERENCES.md"} for k,v in s.items() if k!="build-threejs-scroll-worlds"); print("PINNED")'
|
||||
EXPECT: PINNED
|
||||
EVIDENCE: MET exit=0 marker-found :: PINNED
|
||||
3. One shared helper, both scripts use it, no sha hardcoded.
|
||||
CHECK: [ -f lib/vendor-skills.sh ] && grep -q '^vendor_pinned_skills()' lib/vendor-skills.sh && grep -q 'vendor-skills.sh' install-plugins.sh && grep -q 'vendor-skills.sh' update-all.sh && [ "$(grep -c 'vendor_pinned_skills' install-plugins.sh)" -ge 2 ] && [ "$(grep -c 'vendor_pinned_skills' update-all.sh)" -ge 2 ] && ! grep -qE 'a965851|2686b620' lib/vendor-skills.sh install-plugins.sh update-all.sh link.sh lib/toggle-external.sh && echo LOCK_DRIVEN
|
||||
EXPECT: LOCK_DRIVEN
|
||||
EVIDENCE: MET exit=0 marker-found :: LOCK_DRIVEN
|
||||
4. Hermetic helper suite: list-shape and dict-shape entries, file:// base, tmp+mv, failure leaves nothing, refresh overwrites.
|
||||
CHECK: out=$(make test suite=lib/tests/vendor-skills.test.sh 2>&1); echo "$out" | grep -qE "FAIL=[1-9]" && { echo "$out" | tail -15; exit 1; }; for k in LIST_SHAPE DICT_SHAPE FAIL_LEAVES_NOTHING REFRESH_OVERWRITES SKIP_PRESENT; do echo "$out" | grep -q "PASS $k" || { echo "missing PASS $k"; exit 1; }; done; echo HELPER_SUITE_GREEN
|
||||
EXPECT: HELPER_SUITE_GREEN
|
||||
EVIDENCE: MET exit=0 marker-found :: HELPER_SUITE_GREEN
|
||||
5. Copies and symlink paths gitignored.
|
||||
CHECK: ok=1; for s in scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal scroll-progress-timeline; do git check-ignore -q "skills-external/$s" && git check-ignore -q "skills/$s" || { echo "not ignored $s"; ok=0; }; done; [ "$ok" -eq 1 ] && echo IGNORED
|
||||
EXPECT: IGNORED
|
||||
EVIDENCE: MET exit=0 marker-found :: IGNORED
|
||||
6. link.sh, toggle-external, profile.sh and the four design profiles list the five; the four profiles also list `site-motion` as personal.
|
||||
CHECK: ok=1; for s in scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal scroll-progress-timeline; do grep -q "$s" link.sh && grep -q "$s" lib/toggle-external.sh && grep -q "$s" lib/profile.sh || { echo "not registered $s"; ok=0; }; for p in design web web-full full; do grep -q "^$s" "lib/profiles/$p.profile" || { echo "not in $p: $s"; ok=0; }; done; done; for p in design web web-full full; do grep -qE "^site-motion\s+personal" "lib/profiles/$p.profile" || { echo "site-motion missing in $p"; ok=0; }; done; for p in backend dev; do grep -qE "^(scroll-|site-motion)" "lib/profiles/$p.profile" && { echo "leak into $p"; ok=0; }; done; [ "$ok" -eq 1 ] && echo REGISTERED
|
||||
EXPECT: REGISTERED
|
||||
EVIDENCE: MET exit=0 marker-found :: REGISTERED
|
||||
7. Profile, toggle-external, doctrine-citers and routing-census suites green.
|
||||
CHECK: out=$(make test suite="lib/tests/profile-default.test.sh lib/tests/profile-set-managed.test.sh lib/tests/toggle-external-repo-resolution.test.sh lib/tests/doctrine-citers.test.sh lib/tests/skill-routing-census.test.sh" 2>&1); echo "$out" | grep -qE "FAIL=[1-9]" && { echo "$out" | tail -20; exit 1; }; echo SUITES_GREEN
|
||||
EXPECT: SUITES_GREEN
|
||||
EVIDENCE: MET exit=0 marker-found :: SUITES_GREEN
|
||||
8. agent-skills behaviour intact through the shared helper.
|
||||
CHECK: ok=1; for s in observability-and-instrumentation deprecation-and-migration ci-cd-and-automation; do [ -f "skills-external/$s/SKILL.md" ] || ok=0; done; python3 -c 'import json; d=json.load(open("plugins.lock.json"))["agent-skills"]; assert d["commit"]=="2686b620fc1fed2e8f60c704839c766b8594c6b6"; assert isinstance(d["skills"], list) and len(d["skills"])==3' && [ "$ok" -eq 1 ] && echo AGENT_SKILLS_INTACT
|
||||
EXPECT: AGENT_SKILLS_INTACT
|
||||
EVIDENCE: MET exit=0 marker-found :: AGENT_SKILLS_INTACT
|
||||
9. shellcheck clean on every touched script.
|
||||
CHECK: shellcheck install-plugins.sh update-all.sh link.sh lib/toggle-external.sh lib/profile.sh lib/vendor-skills.sh lib/tests/vendor-skills.test.sh && echo SHELLCHECK_OK
|
||||
EXPECT: SHELLCHECK_OK
|
||||
EVIDENCE: MET exit=0 marker-found :: SHELLCHECK_OK
|
||||
|
||||
## FILE SCOPE
|
||||
- plugins.lock.json, install-plugins.sh, update-all.sh, link.sh, .gitignore
|
||||
- lib/vendor-skills.sh (new), lib/tests/vendor-skills.test.sh (new)
|
||||
- lib/toggle-external.sh, lib/profile.sh, lib/profiles/{design,web,web-full,full}.profile
|
||||
- lib/tests/profile-default.test.sh, lib/tests/profile-set-managed.test.sh, lib/tests/toggle-external-repo-resolution.test.sh (only if they enumerate externals)
|
||||
- skills-external/<five>/ materialized (gitignored)
|
||||
|
||||
## PLAN
|
||||
1. Read install-plugins.sh Step 8e + `pinned_commit`, update-all.sh 7.3, link.sh EXTERNAL_SKILLS, .gitignore blocks, lib/toggle-external.sh, lib/profile.sh, the four design profiles (how emil-design-eng and personal skills are listed).
|
||||
2. `lib/vendor-skills.sh`: lock reader (python3 argv → source/commit/path/skills, normalising list → dict), URL builder honoring `VENDOR_BASE_URL`, per-file tmp+mv loop, skip/refresh, summary lines in the scripts' ok/info/err style (define fallbacks if sourced standalone). Functions ≤ 25 logic lines, 80-char lines.
|
||||
3. install-plugins.sh Step 8e → source the lib, call `vendor_pinned_skills agent-skills` then `vendor_pinned_skills mengto-skills`; update-all.sh 7.3 → same with `refresh`. Remove the now-dead inline loops; keep or fold `pinned_commit`.
|
||||
4. Lock entry; link.sh EXTERNAL_SKILLS += 5; .gitignore both patterns ×5 with a source comment; toggle-external MANAGED_TOOLS += 5; profile.sh MANAGED_EXTERNALS += 5; profiles (five + `site-motion personal`).
|
||||
5. `lib/tests/vendor-skills.test.sh`: temp dir with a fake lock (one list-shape key, one dict-shape key with a references/ file), fixture tree served via `VENDOR_BASE_URL=file://…`, checks LIST_SHAPE, DICT_SHAPE, SKIP_PRESENT, REFRESH_OVERWRITES, FAIL_LEAVES_NOTHING (missing fixture file → no partial file, no tmp). `PASS=n FAIL=m` summary.
|
||||
6. Materialize the five with the helper against the real lock (network); run criteria 1-9.
|
||||
@@ -0,0 +1,50 @@
|
||||
# CONTRACT — site-motion-skill
|
||||
- date: 2026-09-27 | flow: feat (ad-hoc dispatch, /feat gates replayed by the orchestrator) | branch: feature/mengto-site-motion
|
||||
- status: active
|
||||
|
||||
## REQUEST (verbatim — IMMUTABLE)
|
||||
> Write the personal skill `skills/site-motion/SKILL.md` (+ `test-prompts.json` for darwin, same schema as the 32 existing ones): site-level motion choreography for lively modern sites, distilling the invariants of the MengTo motion pack (LRN-141: invariants, never machinery), aligned with rules/web-building.md, BDR-005 (`motion` is the default library; GSAP allowed for scroll choreography when the project already uses it or the effect needs pin/scrub) and the design toolchain. Sections: when to use versus the component-level skills (emil-design-eng, design-motion-principles, impeccable animate) and the audits; gates first (reduced motion renders final states, never shortened animations; content visible without JS, `html.js` gate set only after plugin registration; compositor-only properties, `will-change` only during an animation, offscreen pause, first-viewport CTA never covered by a preloader, no preloader on a timer); engine choice (exactly one smooth-scroll engine; Lenis ↔ ScrollTrigger sync through `gsap.ticker` with `lagSmoothing(0)`; CSS `animation-timeline` first when the effect is plain progress); Astro lifecycle with ClientRouter (init on `astro:page-load`, teardown on `astro:before-swap`, `transition:persist` for canvases, `transition:name` for morphs, test with and without JS); recipes as numbers (reveal at `top 82%`, once; scrub 0.8-1.4 with `ease: "none"` and eased children; sticky card stack scale `0.92 + i*0.015` from the next card `top 78%` → `top 24%`; 0.7-1.8 viewport heights of scroll per story beat; video scrub encoded with `ffmpeg -g 8 -keyint_min 8 -sc_threshold 0 -movflags +faststart`; image sequences cancel stale requests; word split through `TreeWalker` with the original text kept readable and no `aria-label` on paragraphs; progressive blur = stacked `backdrop-filter` layers 0.5 → 64 px in 12.5 % mask bands with the `-webkit-` prefix, top ≤ 12 %, bottom ≤ 65 %; marquee = duplicated track, `translateX(-50%)` linear, `aria-hidden` clone, paused offscreen; magnetic and cursor effects through `gsap.quickTo`; WebGL: one lane per page, pricing decorative only, poster fallback built first, context loss handled, DPR 1.25-1.5 on mobile with 150-300k triangles and 50-90 draw calls, exact progress for navigation and ARIA versus damped progress for the camera; offscreen census through `document.getAnimations()` and route-cycle leak sampling); an upstream-pitfalls list; a verification checklist. Routing: one line in CLAUDE.global.md § Design work, "Build UI" chain, and in lib/design-gate.md's toolchain list, doctrine budget ≤ 320 lines. User go 2026-09-27 ("ok pour 1, l'hybride", case 7).
|
||||
|
||||
## CLARIFICATIONS
|
||||
- Length 140-220 lines, English, frontmatter `name: site-motion` and a `description:` that states what it does then FR+EN triggers ("site mouvementé", "scroll storytelling", "smooth scroll", "hero WebGL", "transitions de page", "Lenis", "ScrollTrigger", "Awwwards"), plus the frontmatter keys the sibling personal skills carry (read skills/feat/SKILL.md and one design-side skill for the shape).
|
||||
- Sources: the upstream texts are already on disk, read them, never re-fetch: /tmp/claude-1000/-home-bchanot-Documents-claude/977f1703-f01d-497a-b794-5b69fafcd35f/scratchpad/mengto/ (11 small skills) and .../scratchpad/mengto-heavy/ (11 heavy ones, extras under x/). Distil; never copy paragraphs.
|
||||
- Never prescribe: glow or gradient hover, reveal on every section, permanent `will-change`, Inter or Geist, preloaders on timers, entrances from `scale(0)`, ease-in exits. Point to rules/web-building.md by path instead of restating it.
|
||||
- Pitfalls to list (found upstream by reading): `clearProps` under reduced motion leaving text hidden behind a visibility gate; `registerPlugin` after the `html.js` gate; per-frame `phi += 0.01` without delta time; WebGL context recreated on every resize; preloader on a fixed timer; `aria-label` on `<p>`; content left at opacity 0 without JS.
|
||||
- Citations of doctrine use the exact heading: `CLAUDE.md § Design work — full toolchain (tiered by scope)`; any other citation must resolve for lib/tests/doctrine-citers.test.sh.
|
||||
- No profile edits (the sibling contract adds `site-motion personal` to the design profiles); no CHANGELOG; no README.
|
||||
- test-prompts.json: ≥ 4 prompts, at least one French, following the existing schema.
|
||||
|
||||
## ACCEPTANCE CRITERIA
|
||||
1. Shape: frontmatter, name, description, length, valid test prompts.
|
||||
CHECK: f=skills/site-motion/SKILL.md; [ -f "$f" ] && [ "$(head -1 "$f")" = "---" ] && grep -q "^name: site-motion$" "$f" && grep -qE "^description:" "$f" && n=$(wc -l < "$f") && [ "$n" -ge 140 ] && [ "$n" -le 220 ] && python3 -c 'import json; d=json.load(open("skills/site-motion/test-prompts.json")); p=d if isinstance(d,list) else next(v for v in d.values() if isinstance(v,list)); assert len(p)>=4' && echo SHAPE
|
||||
EXPECT: SHAPE
|
||||
EVIDENCE: MET exit=0 marker-found :: SHAPE
|
||||
2. Content markers present.
|
||||
CHECK: f=skills/site-motion/SKILL.md; ok=1; for k in "prefers-reduced-motion" "astro:page-load" "astro:before-swap" "transition:persist" "transition:name" "lagSmoothing" "animation-timeline" "TreeWalker" "-webkit-backdrop-filter" "getAnimations" "quickTo" "keyint_min" "top 82%" "0.015" "draw call" "poster" "html.js" "emil-design-eng" "design-motion-principles" "web-building.md"; do grep -qi -- "$k" "$f" || { echo "missing $k"; ok=0; }; done; [ "$ok" -eq 1 ] && echo CONTENT
|
||||
EXPECT: CONTENT
|
||||
EVIDENCE: MET exit=0 marker-found :: CONTENT
|
||||
3. No default-reflex prescriptions.
|
||||
CHECK: f=skills/site-motion/SKILL.md; ! grep -qE "\b(Inter|Geist)\b" "$f" && ! grep -qiE "scale\(0\)[^)]*(entrance|enter|in\b)" "$f" && echo NO_DEFAULT_REFLEXES
|
||||
EXPECT: NO_DEFAULT_REFLEXES
|
||||
EVIDENCE: MET exit=0 marker-found :: NO_DEFAULT_REFLEXES
|
||||
4. Routing wired within budget.
|
||||
CHECK: grep -q "site-motion" CLAUDE.global.md && grep -q "site-motion" lib/design-gate.md && [ "$(wc -l < CLAUDE.global.md)" -le 320 ] && echo ROUTED
|
||||
EXPECT: ROUTED
|
||||
EVIDENCE: MET exit=0 marker-found :: ROUTED
|
||||
5. Citations resolve and the skill routes without collision.
|
||||
CHECK: out=$(make test suite="lib/tests/doctrine-citers.test.sh lib/tests/skill-routing-census.test.sh" 2>&1); echo "$out" | grep -qE "FAIL=[1-9]" && { echo "$out" | tail -15; exit 1; }; echo "$out" | grep -E "^(WARN|FAIL) " | grep -q "site-motion" && { echo "site-motion collides"; echo "$out" | grep -E "site-motion"; exit 1; }; echo CITED_AND_ROUTABLE
|
||||
EXPECT: CITED_AND_ROUTABLE
|
||||
EVIDENCE: MET exit=0 marker-found :: CITED_AND_ROUTABLE
|
||||
6. Every local path the skill names exists.
|
||||
CHECK: ok=1; for p in $(grep -oE "\b(skills-external|skills|rules|lib)/[A-Za-z0-9_./-]+" skills/site-motion/SKILL.md | sed 's/[.,;:)]*$//' | sort -u); do [ -e "$p" ] || { echo "missing $p"; ok=0; }; done; [ "$ok" -eq 1 ] && echo LINKS_OK
|
||||
EXPECT: LINKS_OK
|
||||
EVIDENCE: MET exit=0 marker-found :: LINKS_OK
|
||||
|
||||
## FILE SCOPE
|
||||
- skills/site-motion/SKILL.md (new), skills/site-motion/test-prompts.json (new)
|
||||
- CLAUDE.global.md (one line, § Design work, "Build UI" chain), lib/design-gate.md (toolchain list lines)
|
||||
|
||||
## PLAN
|
||||
1. Read the shape precedents (skills/feat/SKILL.md frontmatter, one design-side personal skill, skills/feat/test-prompts.json), rules/web-building.md, the "Design work" section of CLAUDE.global.md, lib/design-gate.md lines 40-50 and 130-140, and the upstream scratch copies.
|
||||
2. Draft the skill: When to use / not; Gates first; Engine choice; Astro lifecycle; Recipes (numbers); Upstream pitfalls; Verification. Link to the local skills by path.
|
||||
3. test-prompts.json; routing line + design-gate list; run criteria 1-6.
|
||||
@@ -7,6 +7,28 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **`skills/site-motion`** — personal skill for site-level motion
|
||||
choreography (scroll engine choice and Lenis/ScrollTrigger sync, Astro
|
||||
ClientRouter lifecycle, pin/scrub numbers, sticky stacks, video and image
|
||||
scrubbing, WebGL hero lanes and budgets, upstream pitfalls, verification
|
||||
checklist), distilled from the MengTo motion pack (invariants only,
|
||||
LRN-141). Routed into the Build UI toolchain of CLAUDE.global.md and
|
||||
lib/design-gate.md (not on the GATE-BLOCK set). Case 7 of the repo review.
|
||||
- **Five MengTo scroll skills vendored** (`scroll-world-storytelling`,
|
||||
`build-threejs-scroll-worlds` with its five references,
|
||||
`scroll-scrubbed-visual-sequence`, `scroll-scrubbed-word-reveal`,
|
||||
`scroll-progress-timeline`) at a pinned commit (`mengto-skills` entry in
|
||||
plugins.lock.json, text files only, never demos or binaries). The
|
||||
agent-skills curl loop became the shared `lib/vendor-skills.sh`
|
||||
(`vendor_pinned_skills <lock-key> [refresh]`, list or dict lock shapes,
|
||||
`VENDOR_BASE_URL` for the hermetic suite `lib/tests/vendor-skills.test.sh`),
|
||||
used by install-plugins.sh Step 8e and update-all.sh 7.3; refresh keeps
|
||||
the file's convention and skips a skill that was never installed.
|
||||
Registered in link.sh, .gitignore,
|
||||
toggle-external, profile.sh and the design/web/web-full/full profiles
|
||||
(plus `site-motion personal`). Seventeen other MengTo skills were read and
|
||||
skipped: covered locally, buggy (reduced-motion `clearProps`, gate before
|
||||
`registerPlugin`, no-JS opacity 0) or off-domain.
|
||||
- **rules/web-building.md § Write-time reflexes** — stack-agnostic
|
||||
micro-rules borrowed from ibelick/ui-skills (baseline-ui + playbook): dvh
|
||||
and safe-area, paste never blocked, tabular-nums and text-wrap, one
|
||||
|
||||
Reference in New Issue
Block a user