It started with a simple ask: time-saga looks different in prod than it does locally. Ping the URL, see for yourself. So I did — and the prod

two; stale by five entire commits' worth of palette work, gesture handling, splash contrast logic. The kind of gap that doesn't happen from forgetting to deploy once.

It happened from git remote pointing at the wrong place. Prod's checkout had origin set to the old GitHub mirror, 166 commits behind the tangled.org repo where real work actually lands — so every git pull on that box had been quietly succeeding at pulling nothing new. Copied the current time-saga.js over by hand to unblock the immediate ask, then went back and did it properly: generated a fresh deploy key on the box, registered it with tangled.org, repointed origin, confirmed zero real conflicts between what was sitting uncommitted on disk there and what local already had pushed, and did a real git reset --hard onto the correct history. ./plan1.sh deploy's git pull step works correctly from that box now, for the first time in a while.

That opened the door to actually trusting prod enough to chase smaller bugs. A Safari-mobile crash — requestIdleCallback can't find variable — traced back to plan98-shims.js's polyfill being loaded

Firefox never noticed because they have the real API, Safari never implemented it at all. Fixed by dropping async so the shim is guaranteed to run before any deferred module. Found a second latent bug sitting right next to it while I was in there — the polyfill's own fallback referenced an undefined start variable, which would have thrown its own error the moment the fixed version actually ran.

Then a Chrome permission prompt — "access other apps and services on this device" — that turned out to be the browser's Local Network Access gate, tripped by open-clown.js auto-pinging localhost:11434 on every page load looking for a local Ollama that was never going to be there in prod. Patched the client code to skip the fetch entirely when unconfigured, matching a pattern accessibility-mode.js already used correctly. Redeployed, checked again — still hitting it. Turned out the client fix was correct and irrelevant: server.js had its own hardcoded

into every page's injected plan98.env regardless of what .env actually said. The client-side gate was checking for empty and getting a real string every time. Removed the server default; that was the actual bug, one layer up from where I'd been looking.

generic /app/ dev-test route directly made the elf treat its own path as "the app to iframe," which iframed a copy of itself doing the same thing. Excluded its own path from that check.

The most honest moment of the session was the realtime sync question. Scan time-saga's QR code with a phone, swipe, does the display update too? The room-sync mechanism is real and correctly wired — same

room, commit() broadcasting to everyone connected. Except colors weren't syncing either, which shouldn't happen if any of it worked. Traced it all the way down: the geckos relay (multiplayer.js) isn't running on that box at all, and can't start — its native WebRTC dependency never got its prebuilt binary, because the project's dependencies resolve through Deno's npm-compat layer, which skips the install script that would have fetched it. Port 9208, which

unrelated Express app already living on that shared box, not geckos. Asked "can we just point to that one, was it just offline?" — no: even healthy, it's a different wire protocol entirely, geckos over WebRTC signaling versus braid over plain HTTP. Different question than the one that looked like it was being asked. The repo already has the real fix built and waiting — a Podman/Quadlet container setup with a proper npm ci that would install the native binary correctly — just never carried over to this particular box. Got Podman installed; the port collision and cutover are still ahead.

Smaller, and satisfying to finally trace to the end: time-saga's lower third. live-credit's place-self: end had been a no-op the whole time, because the sibling rule forcing height: 100% on every beat left no room within the grid area for "end" to move anything toward. Fixed that, and the background: black credit card in tell-your-story.saga promptly rendered as a giant black slide instead of a bottom bar — the same rule needed removing at its actual source, [name="stage"] > *. Shrinking the demo saga list from eight entries to four then surfaced a third bug for free: a synced or cached sagaIndex from before the trim pointing past the end of the new, shorter array, crashing on

Clamped it at both read sites instead of trusting incoming state to match the current build.

Closed the loop on an accessibility ask — dialogue and action text now render bold, twice the size, white on black — and while checking it rendered right, noticed it wasn't rendering in the project's own font at all. The root style for the whole element had font-family: system-ui, sans-serif with no Recursive in it anywhere; only the list view had ever been patched back. Everything downstream that doesn't declare its own font — which, until today, included the caption text I was just done styling — had been inheriting the wrong one the entire time.

— MAPFAC30-CAFE-BABE-C0DE-DEADBEEF2026

permalink