ABACUS.PRG
WHAT IT IS.
New Year's Eve, 2024: while everyone else was making resolutions, I was writing the merge primitives for a Spotify playlist tool — proof that a good diff algorithm is more satisfying than a countdown. The result is a React + Tailwind front-end that pulls a user's Spotify playlists into two synchronized columns and lets them diff, delete, move, clone, reorder and merge tracks across them. Operations are debounced and cached client-side in src/utils/operations.js, with a change ledger in src/utils/changesManager.js. Server-side (server/server.py, server/playlist_handler.py, server/chat_handler.py) is a thin Tornado stack speaking PKCE OAuth and proxying the Web API, plus a small handler that calls an LLM to suggest a playlist from a natural-language prompt. The build closes with server/Dockerfile (24 lines, head) and deploy.sh (5 lines, sanitised prod/dev envs). It is also the first project whose history explicitly records an LLM-assisted finish: the final commits are tagged "ChatGPT", "AI being requested", and "AI assistant," around the bridge between chat_handler.py and playlist_handler.py.
THE ARC.
Day one (Initial commit, 2024-12-30) is the whole scaffold: package.json, public assets, App.js, Callback.js, LoginButton.js, Playlists.js, the README — 19 files, 489 insertions, all in one commit. Hour two is Navigator.js (104 lines) and a .proxyrc.json so the dev server proxies to localhost:8888. Diff working (2024-12-31) is the first nontrivial refactor: Navigator.css plus 194 lines of JS, the synchronized-scroll seam between left and right lists. New Year's Eve (merging, All merge operations) close the diff/merge primitive set, then New Year's Day splits the 636-line Navigator.js into FilterBox, PlaylistActions, PlaylistDetails, PlaylistList, PlaylistSection, SongList, SongsSection and a useNavigatorState.js hook — the structural turn that the rest of the project rests on. By Jan 1 22:56 the project has Ops cached (all working) (713/466 across eight files).
Next day is the Tailwind rewrite (Introducing, 1035 insertions and 520 deletions across sixteen files), then a ten-day stretch of one screenshot-friendly fix after another — visual bugs, drop issues, deleteList, grid layout, on 401 goto /, loading all playlists, favorites, the Move client to folder rename pass. The closing week is the LLM integration: A server API to produce playlists with ChatGPT (246 insertions, four server files), AI being requested (to wrap up), AI assistant (3 files, 332/−228), and Added dockerfile (head, 24 lines). The generative feature sits above deterministic playlist operations rather than replacing them.
Stack chips: React 18 · Tailwind 3 (tailwind.config.js, postcss.config.js) · Prettier (.prettierrc) · useNavigatorState.js custom hook · changesManager.js change ledger · Tornado + PKCE OAuth (server/server.py) · server/chat_handler.py LLM bridge · Dockerfile + deploy.sh.
WHAT I LEARNED.
Two synchronized columns and a deterministic merge primitive made the comparison legible. The change ledger then gave each operation an inspectable record.
Debounced cached operations separate immediate local feedback from slower network synchronization; the change ledger keeps that boundary visible.
The useful division of labor was deterministic UI logic with a generative layer on top. Suggestions could remain suggestions because the tool still owned the operations.
Tailwind rewrites are a reset, not a refactor: 1035 insertions and 520 deletions in one commit, then
Navigator.css(-298) andindex.css(-672) deleted entirely in the next.