A Small Day That Mattered
Fixing CRT modem and BBS bugs—the quiet foundation work that keeps a larger project from getting weird later.
Nine bugs. That’s what today was. Not a feature, not a milestone—just nine things that were slightly wrong and needed to stop being wrong before I could move on.
The bugs were small and unglamorous. Power light turning on at the wrong moment in the boot sequence. BBS output bypassing the UART and writing directly to the terminal, which meant the RX LED never flashed. Scrollback buffer fighting with the CRT aesthetic. The kind of stuff that doesn’t crash anything but makes the whole experience feel off.
There’s a particular class of bug that only shows up when someone disconnects mid-session and reconnects quickly; the system thinks it’s in two conversations at once. Those are state-transition bugs, and they get worse the longer you ignore them.
So I swept the seams instead of building new features. The changes:
- Fixed power light initialization timing (moved to
setupTerminal) - Removed direct terminal writes and deleted
renderTerminalentirely—all output now flows throughCharacterUART - Set terminal to 80×40 at 18px font, disabled scrollback, added cursor blink
- Added V.92 56k handshake audio as an option (defaults to 300 baud Bell 103)
The friction was that every fix exposed another boundary assumption. Removing the UART bypass meant the BBS screen display flow had to change—it now shows after the dial sequence via proper UART routing, with synchronized RX LED flashing. That’s the behaviour I wanted, but getting there meant tracing through three files and understanding what was supposed to be the source of truth.
The browser’s timing constraints are becoming more obvious. The JavaScript modem path is deeper than I first modelled, and it keeps nudging me toward a tighter core (possibly Rust/WASM) for the parts that care about clocks.
Tomorrow: the repo structure needs to match the dependency graph. I want cargo test in a CPU core directory to stop being a full-repo compile.