Diary

Filtered to games-mahjong. Clear

2026-06-08 sherpa-hubgames-mahjong
# 2026-06-08

## sherpa-hub

Shipped the UI v2 redesign — the hub went from plain light-Tailwind to a dark,
polished dashboard matching the mockup I liked, without giving up the
"stays-current-by-itself" guarantee that's the whole point of the rebuild.

### What we did

Full brainstorm → spec → plan → subagent-driven build cycle:
- Brainstormed the look using the visual companion. Looked at three directions
  first (minimal / dense-dark / playful), then I dropped in a reference mockup
  (the sherpa-dashboard-style dark dashboard with sidebar + summary cards + icon
  tiles + two-button cards) and we built around that.
- Key call: **Path 3 (hybrid).** Adopt the mockup's look, but keep status,
  activity buckets, and all counts 100% auto-derived from GitHub + Render. The
  only hand-set data is set-once and non-rotting: per-app icon (glyph + color)
  in `icons.yaml`, and category tags from GitHub repo topics. This preserves the
  thing that matters most to me — it never goes stale on its own.
- Wrote the spec (`docs/superpowers/specs/2026-05-20-ui-redesign-v2-design.md`,
  decisions UI-1..UI-15) and a 10-task TDD plan, then executed subagent-driven
  with spec + code-quality review on the load-bearing tasks.

### What shipped

- Dark theme, violet accent, left sidebar (bucket filters with live counts +
  Diary/Health links)
- 4 summary stat cards: Total / Live / Active / Needs Attention (the last links
  to /health and shows a green ✓ when nothing's wrong)
- App cards: colored Lucide icon tile, name, description, category tag pills,
  status pill, and two buttons — "Open App ↗" (jumps to the app's URL) and
  "⌁ Status" (drills into the detail page)
- Client-side search + grid/list toggle (no page reload, no backend)
- `/apps` list view dropped — home IS the apps view now (301 redirect)
- Detail, diary, and health pages all restyled dark

### How the icons work (for future me)

`web/app/icons.yaml` maps each slug to a Lucide icon name + a color. The SVGs are
self-hosted via the `lucide-static` npm package and inlined server-side — no CDN,
no icon flash, glyphs color from the tile via currentColor. Lookup is
case-insensitive (matters for repos like `Pips`/`Tanks` that GitHub stores with
capitals). Add a line per new app; anything missing falls back to a slate box.
`reload_icons()` fires on every sync upload so icon edits show up without a restart.

### Decisions recorded

- D-012: UI v2 dark dashboard, Path 3 hybrid (auto-derived + set-once icons)
- D-013: icons.yaml is a deliberate, bounded exception to D-001 (hub-owns-nothing)
  — an icon is a display preference with no source of truth elsewhere, and it
  doesn't rot, so it doesn't reintroduce the legacy failure mode
- D-014: self-host Lucide via lucide-static, inlined (no CDN, no runtime JS)

### Numbers

- 10 plan tasks, all subagent-driven with review gates
- 99 tests pass (49 web + 50 sync)
- Local full-page smoke render confirmed real Lucide SVGs inline on every page
  (17 on the dashboard) — proved the icon pipeline end-to-end, which the unit
  tests alone couldn't
- Pushed to main; Render auto-deploy in flight

## ideas

- Once the deploy lands, fill in `icons.yaml` for any app still showing the slate
  box, and sprinkle GitHub topics on repos I want category tags for. Both
  set-once.
- Favorites was in the mockup but I cut it — no data source and it'd need upkeep.
  If I ever want it, the cheap version is a `favorites: [slugs]` list in a hub
  config file + a star toggle that's really just a filter. Only if I'll actually
  use it.
- The "Needs Attention" card is a nice nudge — when it's >0 it's red with a count,
  when clean it's a green check. Worth watching whether it actually drives me to
  fix orphans/missing-memory, or whether I just ignore it like the legacy hub.

## notes

- Reviewer caught a good one on the icon module: it suggested lowercasing the
  YAML keys to fix `Pips`/`Tanks`, but that would've BROKEN the match (GitHub
  slugs preserve case, so the cache has `Pips` with a capital). Right fix was
  case-insensitive lookup on both sides. Good reminder to verify review feedback
  against the actual data rather than implementing it blindly.
- Subagent-driven dev keeps paying off: the model-vs-data reasoning above, the
  CVE catch last session, the schema-datetime tightening — all came from the
  review gates, not the first-pass implementation.
- Hub URL unchanged: https://sherpa-hub-6psj.onrender.com (dark UI live after the
  deploy finishes). Still need to eyeball it + run a fresh sync.

---

## sherpa-hub — UI v2.1 polish (later same day)

Same-day follow-up after I looked at the live v2 dashboard. Three quick
refinements, brainstormed with the visual companion then built subagent-driven
(5 tasks, 103 tests green).

- **Buttons toned down.** The big filled-purple "Open App" bar was too much. Now
  both buttons are small outlined; "Open ↗" keeps a faint violet tint as the
  primary, "Status" is a quiet outline.
- **Light mode.** Added a sidebar Light/Dark toggle (sun-moon). Default dark,
  remembered in the browser, applied before paint so there's no flash on reload.
  The light palette is a token-override block plus explicit light variants for the
  status pills and the open button (their dark translucent colors were invisible
  on white).
- **The Yeti.** Went down a fun rabbit hole on the app icon — the plain Lucide
  "mountain" looked like a pencil. Generated a few yetis; landed on a flat-style
  "Coding Yeti" logo (shades + hoodie + laptop with `</>`). It's now sherpa-hub's
  icon on its card, the sidebar brand, and the favicon. Built a small extension:
  icons.yaml entries can now carry an `image` field that renders a standalone PNG
  instead of a recolored Lucide glyph — bounded one-app exception, every other app
  keeps the clean Lucide tiles.

### Notes / lessons
- The icon detour was a good reminder that "give me an icon" and "here's a
  gorgeous AI illustration" are different things. Detailed full-color mascots are
  hero images, not 24px tiles. The flat two-tone logo (which even shipped with its
  own small-size preview) was the right kind of asset.
- Verified review feedback against real data again: a reviewer wanted me to
  lowercase the icons.yaml keys to "fix" Pips/Tanks, but GitHub slugs preserve
  case so the cache really has `Pips` — case-insensitive lookup was the correct
  fix, not lowercasing the keys.
- Source yeti images saved in D:\dev\sherpa-server\Images\ (yeti-laptop.png is the
  keeper). Crop recipe is in the v2.1 plan.

### Still to do
- Eyeball the live site after deploy: yeti everywhere, smaller buttons, theme
  toggle. Run a fresh sync so the sherpa-hub *card* picks up the yeti.
- If the yeti's dark hoodie is low-contrast on a dark card, there's a ready
  one-line `.icon-tile:has(.icon-img)` plate fix noted in the plan.

---

## sherpa-hub — end of day: two bugs on the live v2.1 site (paused, resume tomorrow)

Looked at the deployed v2.1 site. Light/dark mode works. Two issues; both
root-caused (systematic-debugging), no fixes applied yet — stopped for the day.

**Bug 1 — yeti not showing.** Server side is verified correct: the image returns
200 image/png live, and the render test proves the sidebar HTML includes the
`<img>`. So it's a browser cache (a stale failed-load from the brief window before
the asset deployed). To do: hard-refresh (Ctrl+Shift+R) and confirm. Likely no code
change.

**Bug 2 — "Open" links go to GitHub, not the live app.** Real root cause: only 13
of 43 apps match a Render service. The matcher requires the Render service name to
EXACTLY equal the repo slug, and many don't — georgianna-mahjong=games-mahjong,
ken-half=half-training-app, four CFB* services=cfb-picks, plus ~27 repos not on
Render (some at kenlill.com). All of those fall back to GitHub. The hub can't guess
these — only I know the mappings/custom domains. Plan: a manual per-app `url:`
override in hub config (like icons.yaml), precedence url > render > github. Need to
decide tomorrow: (A) manual override only, or (B) also auto-pull Render custom
domains. Leaning A. Then I supply the real URLs and re-sync.

Also: the deployed cache is stale (last sync Jun 5) — a fresh sync is needed after
the fix regardless.


---

## games-mahjong + sherpa-hub — evening wrap

**Hub link fix shipped.** Built the per-app `url:` override in icons.yaml
(precedence url > Render > GitHub), read at render time so no re-sync needed.
First mapping: games-mahjong → https://mahjong.kenlill.com (verified live there —
"Georgianna's Mahjong Tutorial"; the old Render service is suspended). 55 web
tests green, pushed. Remaining GitHub-linking apps just need their real URLs
added one line each.

**kenlill.com apex finding:** the root domain is serving a *different, empty*
sherpa-hub instance — no data, and NO auth (open to the world, though only the
empty state shows). The real hub (sherpa-hub-6psj on Render) has the data and
Basic auth. Recommended fix: move the kenlill.com domain to the real hub service.
Decide tomorrow.

**KenBot → mahjong: investigated, correctly STOPPED at pre-flight.** Ken dropped
`D:\Personal\sherpa-kenbot\INTEGRATION.md` (animated talking help character for
the mahjong help screen). Ran the doc's pre-flight gates; both fail:
1. KenBot is React-19-only; the mahjong app is vanilla JS + Vite (no React).
   Recommended path: a tiny React island just for the bot (package ships built
   ESM, so no JSX tooling needed in the host).
2. The doc requires an existing AI help backend; mahjong has none (Supabase Edge
   Functions for game moves only). Natural fit: a new `ask_kenbot` Edge Function
   calling an LLM with keys in Supabase secrets; the ElevenLabs voice proxy can
   be an Edge Function too (doc's Django proxy doesn't apply).
Two decisions for Ken tomorrow: React-island vs vanilla-build, and which
LLM/knowledge should power the bot's answers.

Also: re-cloned games-mahjong to D:\Personal\games-mahjong (local copy had been
lost in the D: cleanup — it was a repo-no-local orphan on the hub Health page),
and created its missing STATUS.md + MEMORY.md with all of the above. Tomorrow's
agenda: hub URL list + kenlill.com domain move + KenBot decisions.