🗺️ Shipping Truth & Hidden Work — the decision cheat sheet

Why this exists. Work kept looking finished while users still got the broken thing. Three structural traps caused it. This page names them, shows exactly what is currently hidden, and tells you what to pick next.

Read time: 4 min. Written for someone who does not know git.


🧠 The one-paragraph mental model

Funday has no remote backup. Everything lives on one disk. Work can hide in four places, only one of which is safe:

PlaceSafe?Why
🟢 Committed to masterPermanent. Survives everything.
🟡 A branchhereAll 61 branches are already inside master. Sticky notes, nothing more.
🔴 A stashInvisible to git status. Easy to forget for months. 5 exist.
🔴 A dirty worktreeA second checkout with unsaved edits. 2 exist.
🔴 A gitignored build artifact❌❌Live in production, in git nowhere. One git clean -fdx reverts the site.

The nastiest one is the last

Production serves files that git has never seen. They are real, they are live, and they are one careless command from gone.


⚖️ The 3 laws that caused the hidden work

1️⃣ 🚚 Iframe games ship without a deploy

GAME_PLUGINS_DIR=/home/usr/funday/games — the server reads games straight off disk.

Edit games/<id>/dist/** → LIVE INSTANTLY. No build. No deploy. No commit.
  • ✅ Fast.
  • ❌ Production can drift from git silently, forever.

2️⃣ 🏗️ entryPoint decides whether your edit reaches anyone

Open games/<id>/funday-plugin.json:

entryPointTypeEditing src/ alone…
src/Game.sveltesvelte-component✅ works → needs a frontend deploy
dist/index.html · build/index.htmliframe-themeabledoes nothing → run that game’s npm run build

This exact trap nearly shipped as a false success

pacman/index.html loads the generated ./pacman.js, not src/*. Fixing the source and declaring victory would have left every user on the old broken bundle. scripts/build-static-iframe-plugins.sh only covers 9 games — everything else is built by hand and goes stale invisibly.

3️⃣ 🎨 DaisyUI owns all colour

Strip it down. Stock semantic classes only: bg-primary + text-primary-content, badge-*, base-content.

  • 🚫 No .text-on-base-*, no color-mix() helpers, no new colour CSS variables, no raw hex.
  • ✅ Deviate only with an explicit stated reason, written in the code.
  • ⚠️ Token patches (--color-*-content) only unlayered in app.css, only light/dark, only when a class cannot clear AA.

*-soft is a trap

alert-soft / badge-soft / btn-soft override the matched content token and paint the hue as text on an 8%-tinted base. Measured 2.10:1 — fails AA. ~30 sites remain.


📦 The hidden-work ledger — per case

Everything below is backed up to ~/funday-wip-backups/ and nothing has been dropped.

🥇 stash@{0} — take this one

What12 lines in scripts/build-atomic.sh
DoesBlocks Svelte dev-compiled code from reaching production
In master?No — verified zero occurrences
VerdictUnique + valuable + tiny. Apply it.

stash@{1} — “before Orbit C1 deploy” · 12 files

games/starter (5) · dev/docs (3) · frontend/src (2) · .env.example → Base is ~4 days old. Small enough to eyeball. Needs your call.

stash@{2} — “skill updates + sisterbrawl dev” · 33 files

frontend/src (9) · games/sisterbrawl (7) · .agents/skills (5) · 3 build scripts → Overlaps work that has since merged. Needs your call.

stash@{3} — “rift-plan-temp” · 229 files

starter (40) · pebble (38) · mines (38) · frontend/src (26) · turtle-cards · mahjong → Looks like an abandoned mass refactor. Likely obsolete.

🗑️ stash@{4} — “cleanup-game-elements” · 602 files, −128,816 lines

yamzy (181) · yamzy2 (122) · panda-publishing (64) · yatzy (44) → 🔍 yamzy, yamzy2, yatzy no longer exist — that cleanup already happened another way. → Mostly obsolete, but it also touches panda-publishing, which is still live. Safest to drop, after a glance.

funday-undo/ worktree — 119 lines

4 scribblaz canvas files, pinned to an 8-day-old commit. Not obviously superseded.

orbit-snatch-2.0.1/ worktree — −12,060 lines

games/settlers pruned + 2 lines in nakama-modules. Looks like deliberate release prep.

The trap when judging these

Every file reports “differs from master” — that mostly means master moved on, not that the stash is newer. Only stash@{0} was small enough to prove either way.


🔎 The verification arsenal

Three committed scripts. Run these instead of trusting a green feeling.

node scripts/audit-contrast.mjs          # WCAG AA: 2 viewports × 2 themes × 9 routes + hover
node scripts/audit-blocked-storage.mjs   # survives a browser that denies storage
node scripts/audit-console-consumers.mjs # both Nakama console consumers actually work

Useful flags: --eval-chunks (module-load coverage) · --scan-chunks (static bundle scan) · --routes /play/x · --no-hover · --json out.json


💀 Hall of traps — every one produced a false all-clear

TrapThe lie it told
🪞 Compositing started behind the elementEvery filled button “failed” at ~1.2
🚪 Auth redirect counted as a pass6 /dev routes “passed” — all measuring the home page
📜 Only the first viewport measured”0 failures” meant 0 above the fold (508 → 1680 nodes)
⏱️ Guessed delay instead of waitingMid-fade sampling → a passing 5.14 badge read as 1.03
🎞️ Scroll-reveal racetext-base-content read 2.73 on near-white
🕵️ typeof localStorage guardGuards nothing — the getter itself throws
🔌 drop_console: trueCrash fixed, but the diagnostic silently stripped from prod

The habit that catches all of these

Confirm every failure with a second reading. A real defect survives a re-read; an artifact does not. Measure the deployed thing, not the source.


🎯 What to pick next

#TaskWhy nowRisk
A⭐ Apply stash@{0}, adjudicate the other 6Only item where delay itself is the risk🟢 Low — all backed up
B🧹 Delete 60 merged branchesgit branch -d refuses unmerged work — self-protecting🟢 None
D🔒 Stop shipping untracked prod codeA fresh clone builds a different site🟡 Policy choice
E🎨 *-soft AA sweep (~30 sites)Last known contrast defect family🟢 Low

Recommended: A → B.

Already closed

C — pinball is fixed. It reloaded itself 2,262 times per 6s; a hardcoded paths.base fought the platform’s asset rewriter, so SvelteKit hard-navigated forever. Fixed in the game (base: '', relative: true — matching turtle-cards and sudoku), not the platform. Now 164 requests, 3 navigations, canvas renders.

A platform-side fix was written and reverted: it broke 3 tests encoding deliberate canonical-root behaviour for blackjack and turtle-cards. Trading two working games for one is not a fix.


✅ Before you say “done”

- Did I run the audit against PRODUCTION, not the source?
- For an iframe game: did I rebuild, or only edit src/?
- Is the artifact gitignored? → tar czf ~/funday-wip-backups/<n>-$(date +%s).tar.gz <paths>
- Did I confirm each failure twice?
- Colour: is it stock DaisyUI, or did I invent a vocabulary?
- Branch → ancestry check → empty dirty-overlap → ff-merge (never commit straight to master)

See also: AGENTS.md §01.4a (game serving) · §01.5 (shared tree) · §01.6 (proof of execution)

Ask Docs

AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

Ctrl+Enter to send