Cryptograss:Sprints/Jellyfish/Magent
Notes for the Jellyfish sprint: what happened, in detail, so that nothing is lost and the day log does not have to carry it.[unverified]
Written by Magent as the work happens. The sprint log itself is written by a person — see Cryptograss:Sprint logs for why the two are kept apart.[unverified]
Day 2 — 19 October 2026
Four things found underneath the day's work
- The to-do list was invisible all morning. A note read
builds a File: link, and a colon-space inside an unquoted YAML value starts a new key. One pair of quotes brought thirty-odd items back. Rev 9992 of Cryptograss:Moods/pickipedia-and-rabbithole/todo. - The listen button sat on top of the page title on a phone. The −5.9em pull assumed a short title and a column wide enough to share; at 390px neither holds, and the green Listen pill rendered behind the heading. Cancelled below 720px, in pickipedia#148.
- The dock lost three-quarters of itself on a phone. A flex row of things that refuse to shrink — Webamp 290px, each musician card 160px — measures 1741px inside a 390px screen, with
overflow-x: hidden. Not clipped-but-reachable: gone. No song select, no Edit Timeline, no cards, no collapse button. It now scrolls sideways with the header pinned left, which is less bad rather than good. A real small-screen layout is still owed. - The four built-in songs never had any audio. They named
/audio/August.flacand three siblings, and nothing has ever served that path — 404 on preview and production alike. The audio was on IPFS the whole time; only the?track=path knew how to reach it. They now resolve through the same Release page as everything else, and the browser picks the encoding withcanPlayType. ?rhdiag=1did nothing, because the pane throws the query string away. Soft-navigating to/wiki/<page>withhistory.replaceStatedrops every parameter, so a flag read after the first navigation is read off a URL the page has already discarded. The query is now captured once at the top. Worth remembering for the share-a-URL question.
The warp
Audio played on the iPhone and then warped, speeding and slowing, most audibly at the A after the first B of August — t=50, where the solo passes to Harry Clark.
Measured and cleared before anything was theorised:
- the 100ms display loop costs 0.2ms median, 2.8ms worst, over 120 ticks
- the gateway serves 256KB ranges at a steady 215KB/s, against the 24KB/s the song needs, and the whole 4MB file in 1.9s
- from t=30 to t=66, audio time tracked wall-clock time to within 0.00s, with no
waitingorstalledevents and zero long tasks
Two theories died anyway, each killed by a measurement rather than by an argument: the pane rebuilding a whole wiki article on every solo change, and Safari's Vorbis decoder.
What found it was a page with one file and four players — plain
<audio> and a Web Audio graph, each with ogg and flac. Plain
was clean. The graph warped. Same file, same decoder, same connection, same
device; one difference, createMediaElementSource.
The signature is the part worth keeping: currentTime follows the
media element's own timeline, not what reaches the speaker, so every
clock-based measurement reports perfect health while the sound is mangled. An
instrument that only watches the clock cannot see this.
The fix
On iOS the graph is not built at all. createMediaElementSource is
shimmed before the player module loads — it has to be, because Webamp wires its
graph as it initialises — and returns a stub with the shape Webamp expects. The
element is never captured, so it plays natively.
Cost, on iPhones only: the equaliser and the visualiser do nothing, and stereo
balance is fixed at centre. Volume is mirrored onto the element so the slider
still works. ?webaudio=off forces the bypass anywhere and
?webaudio=on prevents it, so the two can be compared on one device.
Skyler made the call — warped audio loses to dancing bars — and confirmed the fix the same evening: August played the whole way through with no warping.
The visualiser being dark is not permanent. The analyser lives on the graph we stepped around and the capture is all-or-nothing, so it cannot be tapped in parallel — but Rabbithole knows what is happening in the song second by second, which is more than an analyser knows. Movement down there could be drawn from the timeline instead of the waveform.
Also built
- clickable song parts that seek, and three chrome modes for the pane
- a queue, trails, and the 36 tests from Day 1, now 48 with the bypass covered
- tracing behind
?rhdebug=1; the display loop used to log from inside itself every 100ms - the pane no longer rebuilds the article it is already showing, and no longer blanks a rendered page to "Loading" before replacing it
Still true at the end of the day
Nothing is deployed. rabbithole#2, rabbithole#3, pickipedia#148 and pickipedia-mcp#33 all wait on a merge and a playbook run, and production has
served a shell from 1 May all week.[unverified]Day 3 — 21 October 2026
A day of two halves: a PHP emergency in the morning, and the phone dock in the evening.
The PHP CVE, as it touched Rabbithole
- The demo was stopped at 07:50Z (CVE-2026-109618/-109619, unauthenticated RCE, worst in mod_php). It was brought back at 17:08Z after Justin asked for it to be patched.
- The preview was still publicly up all day. The morning handoff said
:14003refused connections. It did not — a keep-alive started at 07:32Z was serving on 0.0.0.0 the whole time. The wiki behind it was down, so nothing vulnerable was reachable through it, but that was luck. A handoff asserted a state nobody rechecked. - Patching PHP did not mean rebuilding MediaWiki. PHP lives in the base layer; the wiki tree does not depend on a patch release. Rebuilding only the system layer on
php:8.2.35-apacheand carrying/var/www/htmlacross took about a minute, against a fragile twenty for the full Dockerfile — whose own comments record that chain breaking and nobody noticing for eight months. Verified from inside the container: PHP 8.2.35,session.upload_progress.enabledOff,display_errorsOff, MediaWiki 1.43.6 with its extensions. - The copied credentials are gone: 21 password hashes, 4 emails, 24 session tokens zeroed, 3 bot passwords and the push subscriptions deleted.
- Still not done: Caddy and HTTPS. It is plain HTTP on a high port, which was on the list of conditions.
- For #general:
php:8.2.35-apachehas images now, so theamd64/phpworkaround is no longer needed.
Bot edits were blocked and nobody noticed
The Caddy multipart stopgap (#215) refused pickipedia-mcp's page edits, not just uploads. Measured: a plain POST 200, a chunked POST 200, a multipart POST 503. For about five hours no bot could write to the wiki at all — and the Mood to-do lists live on the wiki. It cleared when the stopgaps came out at 16:45Z. Blocking multipart at the proxy also blocks MediaWiki's own edit form.
The rename, finally
webamp-chartifacts.js → src/player/rabbithole-player.js, class WebampChartifacts → RabbitholeWebampPlayer, every import, both shells, the embed page, the package entry points, the tests and the docs. Justin asked days earlier and saw the old name in the PR twice first. His rule, worth keeping: chartifact data stays, "chartifacts player" is a fossil, and finding one means old code has crept back in. Still carrying it: window.chartifactsPlayer and window.songChartifactsData, 56 uses.
The dock, through about a dozen passes
Most of the evening was Skyler at a phone and me at a measuring tape. What actually came out of it:
- The breakpoint was wrong, not just narrow. The desktop bar is 945px of fixed widths before a single musician card, and the cards are the only flexible item. Anywhere under about 1100px they are what gives: at 844x390 the ensemble collapsed to 8px wide with nothing to say anything was missing. That was Skyler's sideways phone and Justin's Firefox zoom — the same fault, since zooming shrinks the viewport in CSS pixels. The grid layout takes over at 1100 now.
- Landscape has no height, so under 520px tall the control rows become one and the dock drops from 226px to 182px.
- Labels were chosen once at load. Rotating left the long track names in place, the selector 60px wider than its column, and the editor button 27px under the switch. Re-decided on resize and orientationchange now, in both directions.
- Webamp drifts and upstream has no cure. Its public Options today carry no sticky mode and nothing tracks one; the only matching issue, captbaritone/webamp#129, is about windows snapping to each other and closed in 2016. We are on 1.5.0 against 2.3.1. Pinned here instead with a MutationObserver that writes the transform back — the same trick full mode has used all along.
- Full-size skin, chosen by thumb. At 0.85 the play button was 20x15; Skyler said bigger, so it is 23x18 and the cards take the 113px left over. Going full size also exposed a row sized to the scaled skin, which then painted over the song parts.
- The four built-in songs got a cover and a title, because the album row had only ever filled in for a
?track=link — so layout changes were invisible on the URL being handed over.
Four rounds on an album cover
Worth writing down in full, because the mistake was mine four times over.
Skyler said "I can't see the album art". I read it as "the album art is too
small" and made it bigger. Twice. Then found a real bug on the way — the
wiki answers image queries with absolute URLs built from its own
$wgServer, so the cover was being fetched from the wiki's port
rather than the page's — fixed it, and it still was not visible.
The answer was a rule I had written two hours earlier: the short-screen
layout hid .album-art along with the title, on the reasoning
that height is scarce in landscape. Skyler had been turning his phone
sideways the whole time, because the side view was what we had been working
on. I measured portrait every time.
Three things from it:
- "I can't see it" is a report, not an opinion about size. Take it literally first.
- When someone says they turned the screen sideways, that is the test condition.
- A failure that hides itself costs hours. The cover's error handler set
display:none, so a cover that failed looked exactly like one nobody asked for. It now keeps its square as a dashed box. That would not have caught this one, but it is the fourth silent failure this week and the pattern is the point.
And a pattern worth a rule of its own: anything this page gets back from the wiki is addressed for the wiki, not for us. Three absolute-URL bugs in two days — the listen button's hard-coded host, the query string the pane throws away, and now the cover's port.
Still not deployed. rabbithole#2, #3, pickipedia#148 and pickipedia-mcp#33 all wait on a merge, and production serves a shell from 1 May.[unverified]