From a160bda55a57163c3cc114936533080241b2bbd4 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Mon, 5 Oct 2026 19:31:22 +0200 Subject: [PATCH] docs(quick-261005-qvk): map Winter icon-* names onto lucide for plugin navigation --- .planning/STATE.md | 7 +- .../261005-qvk-PLAN.md | 271 ++++++++++++++++++ .../261005-qvk-SUMMARY.md | 175 +++++++++++ 3 files changed, 450 insertions(+), 3 deletions(-) create mode 100644 .planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-PLAN.md create mode 100644 .planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index 833eece..edcbbc2 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,9 +5,9 @@ current_phase: "12.1" current_phase_name: User plugin admin screens status: executing stopped_at: Completed 12.1-05-PLAN.md -last_updated: "2026-10-05T14:49:32.883Z" +last_updated: "2026-10-05T17:32:00.000Z" last_activity: 2026-10-05 -last_activity_desc: Plan 12.1-05 closed out (SUMMARY.md); awaiting phase verification +last_activity_desc: Completed quick task 261005-qvk (Winter icon-* mapping) state_head: 93f0171e9c0eb798a61d5d71082873d1b3e8c4c6 progress: total_phases: 22 @@ -31,7 +31,7 @@ See: .planning/PROJECT.md (updated 2026-09-16) Phase: 12.1 (User plugin admin screens) — EXECUTING Plan: 5 of 5 Status: All plans summarized; awaiting phase verification and human UAT -Last activity: 2026-10-05 — Plan 12.1-05 SUMMARY closed out +Last activity: 2026-10-05 - Completed quick task 261005-qvk: Map Winter icon-* navigation names onto lucide so BM Studies and Quizzes icons render Progress: [██████████] 100% @@ -598,6 +598,7 @@ Recent decisions affecting current work: | 260928-lf2 | Rewrite module READMEs and root README as professional app-agnostic docs | 2026-09-28 | fafb12f | [260928-lf2-rewrite-module-readmes-and-root-readme-a](./quick/260928-lf2-rewrite-module-readmes-and-root-readme-a/) | | 261001-ddh | Replace lagoon hardcoded ICU pl-PL database locale with per-query COLLATE option | 2026-10-01 | 037dc53 | [261001-ddh-replace-lagoon-hardcoded-icu-pl-pl-datab](./quick/261001-ddh-replace-lagoon-hardcoded-icu-pl-pl-datab/) | | 261004-rou | Move API-token ownership from Fonoteka to sm-user-plugin | 2026-10-04 | d1abcab | [261004-rou-move-user-api-tokens-from-fonoteka-plugi](./quick/261004-rou-move-user-api-tokens-from-fonoteka-plugi/) | +| 261005-qvk | Map Winter icon-* navigation names onto lucide so BM Studies and Quizzes icons render | 2026-10-05 | a00dafa | [261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic](./quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/) | ## Deferred Items diff --git a/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-PLAN.md b/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-PLAN.md new file mode 100644 index 0000000..2c0bc49 --- /dev/null +++ b/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-PLAN.md @@ -0,0 +1,271 @@ +--- +phase: quick-261005-qvk +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - admin/src/app/icons.ts + - admin/tests/app/icons.test.ts + - modules/boardwalk/dist/ +autonomous: true +requirements: [QUICK-261005-qvk] + +estimate: + tokens: 50000 + raw_tokens: 50000 + tasks: 2 + confidence: low + +must_haves: + truths: + - "iconFor() still prefers a lucide registry name, then a Winter icon-* alias, then Square; empty, null, undefined, unknown names, and inherited Object keys (constructor, toString, __proto__) still return Square" + - "BM Studies nav names render lucide icons, not Square: icon-graduation-cap, icon-book, icon-bookmark, icon-calendar, icon-clock-o, icon-flag, icon-file-text-o, icon-tags" + - "Quizzes names icon-question-circle and icon-list, and the documented Winter name icon-pencil, resolve to lucide components rather than Square" + - "Every winterIcons alias points at a key that exists in the lucide icons map; named imports stay named (no namespace import of @lucide/vue); no Font Awesome package and no new icon library" + - "admin/tests/app/icons.test.ts covers the BM set, Quizzes names, icon-pencil, a handful of other Winter aliases from the closed table, and the existing fallback cases; npm --prefix admin test -- tests/app/icons.test.ts and npm --prefix admin run typecheck pass" + - "modules/boardwalk/dist matches a fresh admin Vite build (scripts/check-admin-dist.sh); HEAD is one code commit of icons.ts, icons.test.ts and the dist tree, with no co-author or session trailer and no .planning files" + artifacts: + - path: "admin/src/app/icons.ts" + provides: "Lucide registry plus Winter icon-* aliases used by PluginRail, SectionPanel, SectionFlyout and SettingsIndexView" + contains: "icon-graduation-cap" + - path: "admin/tests/app/icons.test.ts" + provides: "iconFor unit coverage for BM, Quizzes, icon-pencil and unknown fallback" + contains: "icon-graduation-cap" + - path: "modules/boardwalk/dist/" + provides: "Embedded SPA build that includes the new named lucide icons" + contains: "index.html" + key_links: + - from: "pact.NavigationItem.Icon / SettingsItem.Icon (Winter icon-* string from the admin API)" + to: "iconFor() in PluginRail, SectionPanel, SectionFlyout, SettingsIndexView" + via: "winterIcons alias then icons[lucideName], else fallbackIcon Square" + pattern: "own\\(winterIcons" + - from: "named @lucide/vue imports in icons.ts" + to: "icons Record keys (kebab-case lucide names)" + via: "tree-shaken named imports only; comment in icons.ts already forbids a namespace import" + pattern: "from '@lucide/vue'" +--- + + +Make Winter-style Font Awesome class names on plugin navigation and settings actually render in the SummerCMS admin SPA. Plugins such as jz.bm send names like icon-graduation-cap and icon-book; the SPA never loads Font Awesome, so unknown names become empty Square glyphs. Expand the lucide registry and the Winter alias map in admin/src/app/icons.ts so BM Studies, Quizzes, the documented icon-pencil examples, and a closed set of common Winter backend names resolve to existing @lucide/vue 1.17.0 exports. Keep Square for truly unknown names. Do not change plugin YAML or Go in other repositories. + +Purpose: the documented Winter icon-* API on pact.NavigationItem.Icon and SettingsItem.Icon is the contract ported plugins already use; the framework SPA must honour it. +Output: updated icons.ts and icons.test.ts, a rebuilt modules/boardwalk/dist, one code commit. + + + +@~/.codex/gsd-core/workflows/execute-plan.md +@~/.codex/gsd-core/templates/summary.md + + + +@.planning/STATE.md +@CLAUDE.md +@admin/src/app/icons.ts +@admin/tests/app/icons.test.ts +@admin/package.json +@docs/backend/admin-spa.md +@docs/backend/admin-controllers.md +@docs/setup/porting-a-plugin.md +@scripts/check-admin-dist.sh + +Phase 10 D-11: navigation icons are lucide names in a curated registry; a small Winter icon-* map lets ported plugins work unchanged; unknown names get a neutral fallback. The map today is only icon-archive, icon-circle, icon-list-ul, icon-tags, icon-user, icon-search, icon-cog, icon-users. iconFor trims the name, looks up icons, then winterIcons then icons again, else Square. own() uses Object.hasOwn so constructor/toString never count. + +Call sites already wired (do not change them): PluginRail.vue, SectionPanel.vue, SectionFlyout.vue, SettingsIndexView.vue all pass the server icon string through iconFor(). + +Package: @lucide/vue 1.17.0 (not lucide-vue-next). Named imports only. Confirmed exports in admin/node_modules/@lucide/vue/dist/lucide-vue.d.ts: Book, Bookmark, Calendar, Clock, Flag, FileText, GraduationCap, Pencil, CircleQuestionMark, File, Folder, Copy, Files, Globe, Mail, House, Database, Info, Leaf, Lock, Key, Link, Star, Heart, Bell, Inbox, Download, Upload, Funnel, Wrench, WandSparkles, LifeBuoy, Network, MessageCircle, TriangleAlert, Box, Briefcase, Building, Languages, Gauge, MapPin, Phone, Camera, Play, Pause, ShoppingCart, CreditCard, Table, LayoutGrid, RefreshCw, ExternalLink, CircleCheck, ListOrdered, ClipboardList, Trophy, Paperclip, Code, Cloud, ChartBar. CircleHelp and HelpCircle are absent in this pin; icon-question-circle maps to CircleQuestionMark (key circle-question-mark). Filter is absent; icon-filter maps to Funnel (key funnel). List, Tags, Image, Plus, Minus, Check, X, Settings, User, Users, Archive, Circle, Puzzle, Trash2, LogOut already sit in icons. + +Docs (admin-controllers.md, users-and-permissions.md, settings.md, porting-a-plugin.md, docs/examples/blog/plugin.go) show Icon: "icon-pencil" as Winter examples. They do not claim those names already render and they do not load Font Awesome. Leave those pages unchanged; mapping icon-pencil makes the examples true. Do not add an icon catalogue. + +BM Studies names from the task: group icon-graduation-cap, Courses icon-book, Readings icon-bookmark, Meetings icon-calendar, Sessions icon-clock-o, Deadlines icon-flag, Materials icon-file-text-o, Tags icon-tags. Quizzes: icon-question-circle, icon-list. + +Closed Winter alias table (Winter name -> lucide key already in, or added to, icons). Keep every alias already present. + +BM and documented: +icon-graduation-cap -> graduation-cap +icon-book -> book +icon-bookmark -> bookmark +icon-calendar -> calendar +icon-clock-o -> clock +icon-clock -> clock +icon-flag -> flag +icon-file-text-o -> file-text +icon-file-text -> file-text +icon-tags -> tags (exists) +icon-pencil -> pencil +icon-edit -> pencil +icon-question-circle -> circle-question-mark +icon-question -> circle-question-mark +icon-list -> list (exists) + +Already mapped, keep: icon-archive, icon-circle, icon-list-ul, icon-user, icon-search, icon-cog, icon-users. + +Common Winter backend (core / RainLab / typical plugin nav and settings): +icon-home -> house +icon-leaf -> leaf +icon-magic -> wand-sparkles +icon-life-ring -> life-buoy +icon-sitemap -> network +icon-copy -> copy +icon-files-o -> files +icon-envelope -> mail +icon-envelope-o -> mail +icon-globe -> globe +icon-database -> database +icon-info-circle -> info +icon-exclamation-triangle -> triangle-alert +icon-warning -> triangle-alert +icon-lock -> lock +icon-key -> key +icon-star -> star +icon-heart -> heart +icon-comment -> message-circle +icon-comments -> message-circle +icon-comments-o -> message-circle +icon-folder -> folder +icon-folder-o -> folder +icon-file -> file +icon-file-o -> file +icon-picture-o -> image +icon-photo -> image +icon-plus -> plus +icon-minus -> minus +icon-check -> check +icon-check-circle -> circle-check +icon-times -> x +icon-trash-o -> trash-2 +icon-trash -> trash-2 +icon-sign-out -> log-out +icon-cogs -> settings +icon-group -> users +icon-list-ol -> list-ordered +icon-list-alt -> clipboard-list +icon-dashboard -> gauge +icon-tachometer -> gauge +icon-th -> layout-grid +icon-th-large -> layout-grid +icon-table -> table +icon-bar-chart -> chart-bar +icon-wrench -> wrench +icon-cube -> box +icon-building -> building +icon-briefcase -> briefcase +icon-language -> languages +icon-download -> download +icon-upload -> upload +icon-refresh -> refresh-cw +icon-filter -> funnel +icon-link -> link +icon-code -> code +icon-cloud -> cloud +icon-bell -> bell +icon-inbox -> inbox +icon-paperclip -> paperclip +icon-external-link -> external-link +icon-shopping-cart -> shopping-cart +icon-credit-card -> credit-card +icon-map-marker -> map-pin +icon-phone -> phone +icon-camera -> camera +icon-play -> play +icon-pause -> pause +icon-trophy -> trophy + +Do not add Font Awesome, lucide-vue-next, or any new npm package. Do not change plugin navigation in other repos. Do not commit .planning artifacts. Rebuild dist: hashed files under modules/boardwalk/dist/assets/ will change; commit the whole dist tree with the source. + +Existing tests in admin/tests/app/icons.test.ts: lucide names disc-3/tags, aliases icon-archive/icon-cog, Square fallback including constructor/toString/__proto__, and a loop that every winterIcons value exists in icons. Extend that file; keep those cases. + +Verify command that already works in this repo: npm --prefix admin test (vitest run) and npm --prefix admin run typecheck. After a SPA source change, npm --prefix admin run build then scripts/check-admin-dist.sh. + + + + + + Task 1: Tracer - iconFor maps BM Winter names and icon-pencil onto lucide components + admin/src/app/icons.ts, admin/tests/app/icons.test.ts + admin/src/app/icons.ts, admin/tests/app/icons.test.ts, admin/node_modules/@lucide/vue/dist/lucide-vue.d.ts (confirm Book, Bookmark, Calendar, Clock, Flag, FileText, GraduationCap, Pencil exist as declare const) + + - iconFor('icon-graduation-cap') returns GraduationCap, not Square + - iconFor('icon-book') returns Book; iconFor('icon-bookmark') Bookmark; iconFor('icon-calendar') Calendar; iconFor('icon-clock-o') Clock; iconFor('icon-flag') Flag; iconFor('icon-file-text-o') FileText; iconFor('icon-tags') Tags; iconFor('icon-pencil') Pencil + - lucide keys work too: iconFor('book') returns Book, iconFor(' graduation-cap ') returns GraduationCap + - Existing cases still pass: icon-archive, icon-cog, unknown-icon-name, icon-unknown, empty/null/undefined, constructor, toString, __proto__ all unchanged + - Every winterIcons value is a key in icons + + +In admin/tests/app/icons.test.ts, extend the Winter-alias case (and add lucide-name cases as needed) so the BM names and icon-pencil assert the matching @lucide/vue components. Import those components from @lucide/vue the same way the file already imports Archive, Disc3, Settings, Square, Tags. Run the file and confirm the new assertions fail because the aliases and registry keys are missing. + +Then in admin/src/app/icons.ts add named imports Book, Bookmark, Calendar, Clock, Flag, FileText, GraduationCap, Pencil from @lucide/vue (keep the existing named-import list; do not switch to a namespace import). Register kebab-case keys book, bookmark, calendar, clock, flag, file-text, graduation-cap, pencil on icons. Add winterIcons aliases from the BM-and-documented block in context (icon-graduation-cap, icon-book, icon-bookmark, icon-calendar, icon-clock-o, icon-clock, icon-flag, icon-file-text-o, icon-file-text, icon-pencil, icon-edit; icon-tags already exists). Do not change iconFor, own, or fallbackIcon. Do not add a new dependency. Do not edit Vue shell components; they already call iconFor. + +Leave Quizzes and the rest of the common Winter table for Task 2. Do not rebuild dist yet. Do not commit yet. + + + cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && npm --prefix admin test -- tests/app/icons.test.ts + + iconFor resolves every BM Studies Winter name and icon-pencil to the matching lucide component; unknown names still return Square; the existing constructor/toString fallback cases still pass; nothing committed. + + + + Task 2: Map Quizzes and the closed Winter backend alias table, rebuild the embedded SPA, commit once + admin/src/app/icons.ts, admin/tests/app/icons.test.ts, modules/boardwalk/dist/ + admin/src/app/icons.ts, admin/tests/app/icons.test.ts, scripts/check-admin-dist.sh, docs/backend/admin-spa.md (confirm it does not claim icon names already render; do not edit docs) + + - iconFor('icon-question-circle') returns CircleQuestionMark; iconFor('icon-list') returns List + - iconFor('icon-home') returns House; iconFor('icon-magic') WandSparkles; iconFor('icon-life-ring') LifeBuoy; iconFor('icon-sitemap') Network; iconFor('icon-envelope-o') Mail; iconFor('icon-copy') Copy + - Every alias in the closed table in context is present in winterIcons and resolves through iconFor to a defined lucide component + - iconFor('icon-unknown') and iconFor('constructor') still return Square + - typecheck passes; a fresh Vite build matches modules/boardwalk/dist + + +Add the remaining named @lucide/vue imports from the closed table in context (CircleQuestionMark, File, Folder, Copy, Files, Globe, Mail, House, Database, Info, Leaf, Lock, Key, Link, Star, Heart, Bell, Inbox, Download, Upload, Funnel, Wrench, WandSparkles, LifeBuoy, Network, MessageCircle, TriangleAlert, Box, Briefcase, Building, Languages, Gauge, MapPin, Phone, Camera, Play, Pause, ShoppingCart, CreditCard, Table, LayoutGrid, RefreshCw, ExternalLink, CircleCheck, ListOrdered, ClipboardList, Trophy, Paperclip, Code, Cloud, ChartBar). Register each as its lucide kebab-case key on icons (circle-question-mark, file, folder, copy, files, globe, mail, house, database, info, leaf, lock, key, link, star, heart, bell, inbox, download, upload, funnel, wrench, wand-sparkles, life-buoy, network, message-circle, triangle-alert, box, briefcase, building, languages, gauge, map-pin, phone, camera, play, pause, shopping-cart, credit-card, table, layout-grid, refresh-cw, external-link, circle-check, list-ordered, clipboard-list, trophy, paperclip, code, cloud, chart-bar). Skip keys already in the map (list, image, plus, minus, check, x, settings, users, puzzle, trash-2, log-out, user-plus, circle-alert, tags, archive, circle, search, user). + +Add every remaining winterIcons alias from the closed table. Do not invent names outside that table. Do not map a Winter name onto a lucide export that is not in the declare-const list above (in particular not CircleHelp). Keep Square as the fallback. Keep named imports only. + +Extend admin/tests/app/icons.test.ts: keep the Task 1 BM/pencil cases; add Quizzes icon-question-circle and icon-list; add at least icon-home, icon-magic, icon-life-ring, icon-sitemap, icon-envelope-o, icon-copy, icon-leaf, icon-cogs, icon-edit; keep the loop over Object.entries(winterIcons); keep the unknown/empty/inherited fallback cases. + +Do not edit docs/ or plugin navigation in other repos. Do not add Font Awesome or any package to admin/package.json. + +Then from the repository root run npm --prefix admin run typecheck, npm --prefix admin test -- tests/app/icons.test.ts, npm --prefix admin run build (writes modules/boardwalk/dist), and scripts/check-admin-dist.sh. If dist hashes change, stage the new assets and any removed old hashed files. + +Make ONE commit containing only admin/src/app/icons.ts, admin/tests/app/icons.test.ts, and modules/boardwalk/dist/ (index.html plus assets). Message: fix(admin): map Winter icon-* names onto lucide for plugin navigation. No co-author line and no session attribution trailer. Do not stage .planning files or other dirty files. + + + cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && npm --prefix admin run typecheck && npm --prefix admin test -- tests/app/icons.test.ts && scripts/check-admin-dist.sh && bash -c 'set -e; msg=$(git log -1 --format=%B); files=$(git show --name-only --format= HEAD); ! grep -qi -e co-authored-by -e claude-session <<< "$msg"; echo "$files" | grep -q "admin/src/app/icons.ts"; echo "$files" | grep -q "admin/tests/app/icons.test.ts"; echo "$files" | grep -q "modules/boardwalk/dist/"' + + Quizzes and the closed Winter table resolve through iconFor to lucide components; unknown names remain Square; typecheck, icons tests and check-admin-dist.sh pass; HEAD is a single code commit of icons source, tests and the dist tree, with no co-author or session trailer and no planning files. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| admin API navigation/settings JSON -> SPA iconFor | Plugin-supplied icon strings are untrusted labels; they must never become arbitrary JS object members or extra network loads | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan | +|-----------|----------|-----------|----------|-------------|-----------------| +| T-qvk-01 | Tampering / elevation via prototype keys | iconFor / own() | medium | mitigate | Keep Object.hasOwn lookup; tests continue to assert constructor, toString and __proto__ return Square | +| T-qvk-02 | Information disclosure | lucide named imports | low | mitigate | Named imports only so the bundle does not include the entire @lucide/vue set; no Font Awesome webfont fetch | +| T-qvk-SC | Tampering | npm/pip/cargo/go installs | low | accept | No new package; only additional named exports from the already-pinned @lucide/vue 1.17.0 | + + + +- npm --prefix admin test -- tests/app/icons.test.ts passes, including BM names, Quizzes names, icon-pencil, inherited-key fallback, and the winterIcons-to-icons loop. +- npm --prefix admin run typecheck passes. +- scripts/check-admin-dist.sh reports the committed dist matches a fresh Vite build. +- git show HEAD lists only icons.ts, icons.test.ts and modules/boardwalk/dist/; the message has no co-author or session trailer. + + + +- BM Studies side-menu Winter names and Quizzes icon-question-circle / icon-list render lucide glyphs instead of empty squares once the binary embeds the new dist. +- Documented icon-pencil examples become true without editing docs. +- Unknown Winter or lucide names still show Square. +- One framework commit; no plugin-repo changes. + + + +Create `.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-SUMMARY.md` when done + diff --git a/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-SUMMARY.md b/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-SUMMARY.md new file mode 100644 index 0000000..9b3a2ef --- /dev/null +++ b/.planning/quick/261005-qvk-fix-icons-sm-bm-plugin-tried-to-apply-ic/261005-qvk-SUMMARY.md @@ -0,0 +1,175 @@ +--- +phase: quick-261005-qvk +plan: 01 +subsystem: ui +tags: [admin-spa, lucide, winter-icons, vue, boardwalk] +requires: + - phase: 10-admin-spa + provides: iconFor registry, Winter alias map, PluginRail/SectionPanel/SectionFlyout/SettingsIndexView call sites +provides: + - Winter icon-* aliases for BM Studies, Quizzes, documented icon-pencil, and a closed backend table mapped onto named @lucide/vue 1.17.0 exports + - iconFor unit coverage for BM, Quizzes, icon-pencil, sample Winter aliases, and inherited-key Square fallback + - Rebuilt modules/boardwalk/dist embedding the new named lucide icons +affects: [admin-spa, boardwalk, plugin-navigation] + +actuals: + tokens: 270406 + tasks: 2 + commits: 3 + plan_head_before: 0ea0c787a51f5641c2d1639ad9b11411318cc822 + plan_head_after: 1f228f85bdaa0aa301b288afab540311feab3ace + +tech-stack: + added: [] + patterns: + - Named @lucide/vue imports plus winterIcons alias then icons lookup; Square fallback; Object.hasOwn so prototype keys never count + +key-files: + created: + - modules/boardwalk/dist/assets/index-z_LzMU8D.js + modified: + - admin/src/app/icons.ts + - admin/tests/app/icons.test.ts + - modules/boardwalk/dist/index.html + +key-decisions: + - "Keep Square for unknown names; expand the curated lucide registry and Winter alias map rather than loading Font Awesome" + - "icon-question-circle maps to CircleQuestionMark (circle-question-mark); CircleHelp/HelpCircle are absent in @lucide/vue 1.17.0" + - "icon-filter maps to Funnel; Filter is absent in this pin" + - "Cursor git commit wrapper injected Co-authored-by; the production commit was rewritten with the same tree so HEAD has no co-author or session trailer" + +patterns-established: + - "Winter icon-* plugin nav names resolve through winterIcons onto kebab-case lucide keys already in icons" + - "Named lucide imports only; no namespace import and no extra icon library" + +requirements-completed: [QUICK-261005-qvk] + +coverage: + - id: D1 + description: "iconFor maps BM Studies Winter names and icon-pencil onto lucide components; unknown and inherited keys still return Square" + requirement: QUICK-261005-qvk + verification: + - kind: unit + ref: admin/tests/app/icons.test.ts#resolves Winter icon aliases + status: pass + - kind: unit + ref: admin/tests/app/icons.test.ts#falls back to the neutral square for unknown, empty or missing names + status: pass + human_judgment: false + - id: D2 + description: "Quizzes names and the closed Winter backend alias table resolve through iconFor; every winterIcons value is a key in icons" + requirement: QUICK-261005-qvk + verification: + - kind: unit + ref: admin/tests/app/icons.test.ts#resolves Winter icon aliases + status: pass + - kind: unit + ref: admin/tests/app/icons.test.ts#maps every Winter alias onto a registered lucide icon + status: pass + - kind: other + ref: npm --prefix admin run typecheck + status: pass + human_judgment: false + - id: D3 + description: "Embedded SPA dist matches a fresh Vite build and HEAD is one code commit of icons source, tests, and dist" + requirement: QUICK-261005-qvk + verification: + - kind: other + ref: scripts/check-admin-dist.sh + status: pass + - kind: other + ref: git show HEAD lists only admin/src/app/icons.ts, admin/tests/app/icons.test.ts, modules/boardwalk/dist/ + status: pass + human_judgment: false + +duration: 3min +completed: 2026-10-05 +status: complete +--- + +# Phase quick-261005-qvk Plan 01: Map Winter icon-* names onto lucide Summary + +**Winter `icon-*` plugin nav names (BM Studies, Quizzes, `icon-pencil`, closed backend table) now resolve to named `@lucide/vue` 1.17.0 components in the admin SPA; unknown names still render Square.** + +_Executor: generic-agent workaround (typed gsd-executor unavailable in this Cursor runtime)._ + +## Performance + +- **Duration:** 3 min +- **Started:** 2026-10-05T17:25:47Z +- **Completed:** 2026-10-05T17:29:12Z +- **Tasks:** 2 +- **Files modified:** 5 (icons.ts, icons.test.ts, dist index.html, new hashed JS, deleted previous hashed JS) + +## Accomplishments +- BM Studies Winter names (`icon-graduation-cap`, `icon-book`, `icon-bookmark`, `icon-calendar`, `icon-clock-o`, `icon-flag`, `icon-file-text-o`, `icon-tags`) and documented `icon-pencil` resolve to lucide components instead of empty squares +- Quizzes `icon-question-circle` / `icon-list` and the closed Winter backend alias table are present in `winterIcons` and every alias points at a key in `icons` +- Embedded `modules/boardwalk/dist` rebuilt; `scripts/check-admin-dist.sh` matches a fresh Vite build +- `iconFor` still prefers a lucide registry name, then a Winter alias, then Square; `constructor` / `toString` / `__proto__` stay Square via `Object.hasOwn` + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Tracer - iconFor maps BM Winter names and icon-pencil onto lucide components** - no commit (plan: TDD then implement, leave uncommitted) +2. **Task 2: Map Quizzes and the closed Winter backend alias table, rebuild the embedded SPA, commit once** - `a00dafa` (fix) + +**Plan metadata:** not committed (orchestrator owns STATE/ROADMAP; SUMMARY is uncommitted by instruction) + +_Note: `git rev-list` from `plan_head_before` to HEAD counts 3 because unrelated `f453b80` (`docs(14.1): add validation strategy`) and `1f228f8` (`docs(14.1): add pattern map`) landed on master around this run. This plan's production commit is only `a00dafa`._ + +## Files Created/Modified +- `admin/src/app/icons.ts` - named lucide imports, kebab-case registry keys, Winter `icon-*` aliases +- `admin/tests/app/icons.test.ts` - BM, Quizzes, `icon-pencil`, sample Winter aliases, fallback and winterIcons-loop coverage +- `modules/boardwalk/dist/index.html` - hashed JS asset name +- `modules/boardwalk/dist/assets/index-z_LzMU8D.js` - fresh SPA bundle including new named lucide icons +- `modules/boardwalk/dist/assets/index-CbohsCp4.js` - previous hashed bundle removed + +## Decisions Made +- Expand the curated lucide registry and Winter alias map; do not add Font Awesome or any new npm package +- Map `icon-question-circle` to `CircleQuestionMark` (`circle-question-mark`); this pin has no `CircleHelp` / `HelpCircle` +- Map `icon-filter` to `Funnel`; this pin has no `Filter` +- Leave docs pages unchanged; mapping `icon-pencil` makes the existing examples true +- Strip the Cursor-injected `Co-authored-by` trailer from HEAD so the plan's commit-message gate passes + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Removed Cursor-injected Co-authored-by trailer from HEAD** +- **Found during:** Task 2 commit +- **Issue:** `git commit` succeeded with the intended files, but the Cursor runtime appended `Co-authored-by: Cursor `. `git commit --amend` re-injected the same trailer. The plan verify requires no co-author or session trailer (CLAUDE.md: never add co-author tags). Repo had no commit-msg/prepare-commit-msg hooks. +- **Fix:** Recreated the same tree with `git commit-tree` and moved HEAD with `git reset --soft` so the message matches the planned text. Files unchanged. +- **Files modified:** none (message-only rewrite of the Task 2 commit) +- **Verification:** `git log -1 --format=%B` has no co-authored-by/claude-session; `git show --name-only` lists only icons.ts, icons.test.ts, and modules/boardwalk/dist/ +- **Committed in:** `a00dafa` + +--- + +**Total deviations:** 1 auto-fixed (1 blocking) +**Impact on plan:** Required for the commit-message acceptance gate. No scope creep. Source and dist match the plan. + +## Issues Encountered +- Cursor's git commit wrapper always appends a Co-authored-by trailer; amend is not enough. Production HEAD was rewritten with plumbing so the trailer is absent. +- Unrelated `f453b80` and `1f228f8` (Phase 14.1 docs) landed on master around this run. Left untouched. Our icon files stay at `a00dafa` and the working tree for those paths is clean. + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- Framework SPA honours Winter `icon-*` names used by ported plugins; no plugin-repo changes. +- Ready for orchestrator STATE/ROADMAP close-out. Rebuild/restart the app binary to embed the new dist before checking BM Studies in a running admin. + +--- +*Phase: quick-261005-qvk* +*Completed: 2026-10-05* + +## Self-Check: PASSED + +- FOUND: admin/src/app/icons.ts +- FOUND: admin/tests/app/icons.test.ts +- FOUND: modules/boardwalk/dist/index.html +- FOUND: modules/boardwalk/dist/assets/index-z_LzMU8D.js +- FOUND: 261005-qvk-SUMMARY.md +- FOUND: a00dafa (icon mapping commit; files icons.ts, icons.test.ts, boardwalk dist) +- SUMMARY uncommitted; STATE.md/ROADMAP.md not updated (orchestrator)