chore(memory): doctor vendored check — contract, CHANGELOG, BDR-104 amendment, journal
This commit is contained in:
@@ -1308,3 +1308,4 @@ Branch feature/user-writing-web-rules, UNMERGED (human gate).
|
||||
- **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]].
|
||||
- **Amendment 2026-09-28**: the two LOW caveats closed on user ask (415b44e): `re.fullmatch` guard, `commit`/`source`/`path` validated before URL construction, 4 more hermetic cases (12). Security PASS, verifier CONFORME 9/9.
|
||||
- **Amendment 2026-09-28 (doctor)**: `make doctor` now checks every vendored external (6394fa7, feature/doctor-vendored-skills): lock files present, symlink per active profile, parked ≠ failed, hints. Lib sourceable for the hermetic suite (11 cases); doctor mirrors `active_profile()` instead of sourcing profile.sh (its main runs on source). Security: lock shape-validated, allowlists on profile/item names. Closes the gap that emil/frontend-design/motion had since their install.
|
||||
|
||||
@@ -533,3 +533,4 @@ rules:
|
||||
- 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).
|
||||
- User: "fais les deux low, et après on merge". Hardening by fresh executor (415b44e): fullmatch guard + lock field validation, 12-case suite; verifier CONFORME 9/9, security PASS 0 findings, full make test 36 suites green minus 2 pre-existing T16a. Merge of feature/mengto-site-motion into develop follows.
|
||||
- User go: feature/mengto-site-motion merged into develop via `gitflow finish` → d3633db, no conflict (develop had not moved), pushed, local + origin copies removed by the lib. develop == origin/develop, no working branch anywhere. The whole review is on develop: cases 1-5 (yesterday) + case 7 (today). Open for the user: `make link` + `bash lib/profile.sh apply full` (8 vendored externals to symlink), `rm -rf /tmp/mengto-verify /tmp/tmp.AAyJzvufO6`.
|
||||
- User: "tout cela s'installe et se met à jour comme le reste ?" → traced: install/plugin/update/link all cover the 8 vendored skills; only `make doctor` was blind to curl-vendored externals (since emil). User go → /feat by hand: `lib/doctor-vendored.sh` + doctor section + README (6394fa7); gates MET, verifier CONFORME ×2, security PASS ×2 after one re-dispatch (MEDIUM traceback leak on malformed lock, LOW allowlists). 37 suites green minus 2 pre-existing T16a. feature/doctor-vendored-skills UNMERGED — human gate. Live: 129 skills in the census, 11 externals ✓ in doctor.
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# TODO
|
||||
|
||||
## 2026-09-28 — make doctor checks the vendored externals (feature/doctor-vendored-skills)
|
||||
User go "ok ajoute le check doctor" after the install/update/link trace: doctor.sh only
|
||||
checked the gstack submodule; emil, frontend-design, motion and the 8 curl-vendored
|
||||
skills were invisible. Contract `.claude/tasks/contracts/2026-09-28-doctor-vendored-*`.
|
||||
- [x] D1 6394fa7 `lib/doctor-vendored.sh` `check_vendored_skills`: lock expectations (list /
|
||||
dict / single-path), link.sh EXTERNAL_SKILLS, profile-aware symlink check,
|
||||
hints `make plugin` / `make link`; doctor.sh section; README line; hermetic suite.
|
||||
- [x] D2 gates MET, verifier CONFORME ×2, security PASS ×2 (1 re-dispatch: malformed-lock
|
||||
traceback → warn, allowlists), 37 suites green minus 2 T16a, CHANGELOG, BDR-104
|
||||
amendment, journal. UNMERGED — human gate.
|
||||
|
||||
## 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
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# CONTRACT — doctor-vendored
|
||||
- date: 2026-09-28 | flow: feat (ad-hoc dispatch, /feat gates replayed by the orchestrator) | branch: feature/doctor-vendored-skills
|
||||
- status: active
|
||||
|
||||
## REQUEST (verbatim — IMMUTABLE)
|
||||
> Add a `make doctor` check for the externally vendored skills, which doctor.sh ignores today (it only checks the gstack submodule). New `lib/doctor-vendored.sh` exposing `check_vendored_skills <repo> <claude_home> [profile_file]`, sourced and called by doctor.sh in a new "Vendored skills" section right after the gstack section. Expected state: (1) every plugins.lock.json entry with `managed_by: curl` has its files under `skills-external/`: `skills` as a list → `<name>/SKILL.md` each; `skills` as a dict → every listed file; single-file `path` shape (emil-design-eng) → `<key>/SKILL.md`; (2) every name in link.sh's `EXTERNAL_SKILLS` array has `skills-external/<name>/SKILL.md` and, when the name is listed in the active profile file (or when no profile file is given), a symlink `<claude_home>/skills/<name>` → `<repo>/skills-external/<name>`; a name absent from the active profile is reported as parked, not failed. Outcomes use doctor's helpers: `fail` "<name>: <what is missing> — run: make plugin" for files, `fail` "<name>: symlink missing/wrong — run: make link (or: bash lib/profile.sh apply <profile>)" for links, `info` "<name>: parked by profile <p>", `pass` "<name>: vendored + linked" otherwise, `warn` when the lock or link.sh cannot be read. Hermetic suite `lib/tests/doctor-vendored.test.sh`. README's doctor line names the new check. User go 2026-09-28 ("ok ajoute le check doctor").
|
||||
|
||||
## CLARIFICATIONS
|
||||
- The lib defines fallback `pass/fail/warn/info` only when the caller has not (same `declare -F` guard as lib/vendor-skills.sh) so doctor.sh's counters (`ERRORS`, `WARNS`) keep working.
|
||||
- Lock parsing with python3 via argv (never string-spliced); `EXTERNAL_SKILLS` parsed from link.sh with a single-purpose grep/sed of the array line(s), tolerant to the multi-line array.
|
||||
- Active profile in doctor.sh: resolve the way lib/profile.sh's `active_profile()` does (read its code; the cache path it reads; no `claude` invocation); pass the profile file path `lib/profiles/<name>.profile` to the check; if it cannot be resolved, call the check without a profile file (every external expected linked).
|
||||
- A name in the profile counts whatever its label column says (external / personal), match on the first token of the line.
|
||||
- Functions ≤ 25 logic lines, 80-char lines, ≤ 5 params, ≤ 5 locals.
|
||||
- Suite: fixture repo under mktemp with a fake lock (list, dict with a references/ file, single-path shapes), a fake link.sh holding an `EXTERNAL_SKILLS=(...)` array, a fake `<claude_home>/skills` dir and a fake profile file; cases print `PASS <NAME>`: ALL_PRESENT, FILE_MISSING, DICT_FILES_COMPLETE (dict entry missing one references file → fail names that file), SYMLINK_MISSING_ACTIVE, SYMLINK_WRONG_TARGET, SYMLINK_PARKED (name absent from the profile → info, no fail), NO_PROFILE_EXPECTS_LINK, LOCK_UNREADABLE (warn, rc 0). `PASS=n FAIL=m` summary.
|
||||
- doctor.sh is read-only; the executor MAY run `bash doctor.sh` live for the criterion below (it inspects, never writes).
|
||||
|
||||
## ACCEPTANCE CRITERIA
|
||||
1. Lib exists and doctor.sh is wired.
|
||||
CHECK: [ -f lib/doctor-vendored.sh ] && grep -q '^check_vendored_skills()' lib/doctor-vendored.sh && grep -q 'doctor-vendored.sh' doctor.sh && grep -q 'check_vendored_skills' doctor.sh && echo WIRED
|
||||
EXPECT: WIRED
|
||||
EVIDENCE: MET exit=0 marker-found :: WIRED
|
||||
2. Hermetic suite green with every case.
|
||||
CHECK: out=$(make test suite=lib/tests/doctor-vendored.test.sh 2>&1); echo "$out" | grep -qE "FAIL=[1-9]" && { echo "$out" | tail -15; exit 1; }; for k in ALL_PRESENT FILE_MISSING DICT_FILES_COMPLETE SYMLINK_MISSING_ACTIVE SYMLINK_WRONG_TARGET SYMLINK_PARKED NO_PROFILE_EXPECTS_LINK LOCK_UNREADABLE; do echo "$out" | grep -q "PASS $k" || { echo "missing PASS $k"; exit 1; }; done; echo SUITE_GREEN
|
||||
EXPECT: SUITE_GREEN
|
||||
EVIDENCE: MET exit=0 marker-found :: SUITE_GREEN
|
||||
3. Live doctor on this machine: the eleven externals pass.
|
||||
CHECK: out=$(bash doctor.sh 2>&1); ok=1; for s in emil-design-eng frontend-design design-motion-principles observability-and-instrumentation deprecation-and-migration ci-cd-and-automation scroll-world-storytelling build-threejs-scroll-worlds scroll-scrubbed-visual-sequence scroll-scrubbed-word-reveal scroll-progress-timeline; do echo "$out" | grep -qE "✓.*\b$s\b" || { echo "no pass line for $s"; ok=0; }; done; [ "$ok" -eq 1 ] && echo LIVE_PASS
|
||||
EXPECT: LIVE_PASS
|
||||
EVIDENCE: MET exit=0 marker-found :: LIVE_PASS
|
||||
4. shellcheck clean.
|
||||
CHECK: shellcheck doctor.sh lib/doctor-vendored.sh lib/tests/doctor-vendored.test.sh && echo SHELLCHECK_OK
|
||||
EXPECT: SHELLCHECK_OK
|
||||
EVIDENCE: MET exit=0 marker-found :: SHELLCHECK_OK
|
||||
5. README names the check; doctrine citations resolve.
|
||||
CHECK: grep -qi "vendored" README.md && out=$(make test suite=lib/tests/doctrine-citers.test.sh 2>&1) && ! echo "$out" | grep -qE "FAIL=[1-9]" && echo DOC_OK
|
||||
EXPECT: DOC_OK
|
||||
EVIDENCE: MET exit=0 marker-found :: DOC_OK
|
||||
|
||||
## FILE SCOPE
|
||||
- lib/doctor-vendored.sh (new), lib/tests/doctor-vendored.test.sh (new)
|
||||
- doctor.sh (source line + one section), README.md (the `make doctor` / `bash doctor.sh` description lines)
|
||||
|
||||
## PLAN
|
||||
1. Read doctor.sh (helpers lines 12-15, `check_symlink` 38, the gstack section ~90-118, `check_automode` 258 + its call 310, the summary), lib/vendor-skills.sh (lock read pattern, fallback helpers), lib/profile.sh `active_profile()` + `read_profile()`, link.sh lines 90-105, one hermetic suite for the style.
|
||||
2. lib/doctor-vendored.sh: `_dv_lock_expectations` (python3 argv → lines `<name>\t<file>`), `_dv_link_names` (parse EXTERNAL_SKILLS), `_dv_profile_has <file> <name>`, `_dv_check_files`, `_dv_check_link`, `check_vendored_skills`.
|
||||
3. doctor.sh: source the lib; section header in the file's style; resolve the profile file; call the check.
|
||||
4. README lines; suite; run criteria 1-5.
|
||||
@@ -7,6 +7,17 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **`make doctor` checks the vendored externals** — new
|
||||
`lib/doctor-vendored.sh` (`check_vendored_skills`), wired into doctor.sh
|
||||
after the gstack section: every curl-pinned entry of plugins.lock.json
|
||||
has its files under `skills-external/` (list, dict or single-path lock
|
||||
shapes), every `EXTERNAL_SKILLS` name of link.sh is symlinked into
|
||||
`~/.claude/skills/` when the active profile lists it, parked names are
|
||||
reported not failed, hints `make plugin` / `make link`. Lock entries are
|
||||
shape-validated (a malformed lock yields one warn, never a traceback) and
|
||||
profile, skill and file names pass an allowlist before becoming paths.
|
||||
Until now doctor only checked the gstack submodule. Hermetic suite
|
||||
`lib/tests/doctor-vendored.test.sh`, 11 cases.
|
||||
- **`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
|
||||
|
||||
Reference in New Issue
Block a user