Task 03ef0bb3 (Feature e0855415), built on 60d1594.
One canonical registry: tools/icons/curated-icons.json is the single source of truth (36 Lucide + 22 Font Awesome Free solid, name+label), and tools/icons/generate.mjs writes byte-identical admin/src/icons/registry.generated.ts and frontend/src/icons/registry.generated.ts. Generated data is framework-agnostic (viewBox + path d for lucide/fa, emoji text for emoji); resolveIcon() maps lucide:/fa:/emoji:/legacy bare and returns a fallback for unknown/empty, matching the backend's read normalizer. Both bundles consume it with no CDN and no runtime fetch; only curated FA glyphs.
Evidence at 14fe912: TZ=UTC uv run pytest -q = 2072 passed; cd admin && npm test = 250 passed; cd admin && npm run build ok; cd frontend && npm run build ok; node tools/icons/generate.mjs --check exit 0. Drift test fails if a generated copy or the JSON is edited independently. No tsbuildinfo/node_modules committed.
Task 03ef0bb3 (Feature e0855415), built on 60d1594.
One canonical registry: `tools/icons/curated-icons.json` is the single source of truth (36 Lucide + 22 Font Awesome Free solid, name+label), and `tools/icons/generate.mjs` writes byte-identical `admin/src/icons/registry.generated.ts` and `frontend/src/icons/registry.generated.ts`. Generated data is framework-agnostic (viewBox + path `d` for lucide/fa, emoji text for emoji); `resolveIcon()` maps lucide:/fa:/emoji:/legacy bare and returns a fallback for unknown/empty, matching the backend's read normalizer. Both bundles consume it with no CDN and no runtime fetch; only curated FA glyphs.
Evidence at 14fe912: `TZ=UTC uv run pytest -q` = 2072 passed; `cd admin && npm test` = 250 passed; `cd admin && npm run build` ok; `cd frontend && npm run build` ok; `node tools/icons/generate.mjs --check` exit 0. Drift test fails if a generated copy or the JSON is edited independently. No tsbuildinfo/node_modules committed.
tools/icons/curated-icons.json is the one hand-edited list (the 36 curated
Lucide icons plus 22 Font Awesome Free solid chore icons, name + label).
tools/icons/generate.mjs reads it, takes path data offline from the pinned
lucide-react and @fortawesome/free-solid-svg-icons packages, converts Lucide
circles/rects/lines to paths, and writes the same plain-data module (viewBox
+ path strings, emoji text, resolveIcon parser with a fallback entry) into
admin/src/icons and frontend/src/icons. No CDN, no runtime fetch.
The admin Definitions tab now draws its Lucide set from the registry
(lucide-react becomes a generator-only dev dependency); the panel quest log
renders lucide:, fa: and emoji: icons, falling back to the star. Drift tests
in Vitest and pytest fail if the source or either artefact is edited alone.
Task: 03ef0bb3-8228-4be6-bb73-ee8bb72c2f0f
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Task 03ef0bb3 (Feature e0855415), built on
60d1594.One canonical registry:
tools/icons/curated-icons.jsonis the single source of truth (36 Lucide + 22 Font Awesome Free solid, name+label), andtools/icons/generate.mjswrites byte-identicaladmin/src/icons/registry.generated.tsandfrontend/src/icons/registry.generated.ts. Generated data is framework-agnostic (viewBox + pathdfor lucide/fa, emoji text for emoji);resolveIcon()maps lucide:/fa:/emoji:/legacy bare and returns a fallback for unknown/empty, matching the backend's read normalizer. Both bundles consume it with no CDN and no runtime fetch; only curated FA glyphs.Evidence at
14fe912:TZ=UTC uv run pytest -q= 2072 passed;cd admin && npm test= 250 passed;cd admin && npm run buildok;cd frontend && npm run buildok;node tools/icons/generate.mjs --checkexit 0. Drift test fails if a generated copy or the JSON is edited independently. No tsbuildinfo/node_modules committed.Independent Codex gpt-5.6-terra review completed for this exact commit.