The router was fine. I want to be clear about that up front, because everything that follows is my own fault. It did its job, it had done its job for a couple of years, and it owed me nothing. But it was on the list of devices that the open firmware projects supported, and I had a free Saturday, and "the stock firmware never gets updates anyway" is a very seductive thing to tell yourself when you are about to do something daft.
So I flashed it. And then I had a brick.
How it went wrong
The flash itself appeared to go fine. The web uploader accepted the image, chewed on it, rebooted. Then nothing. No lights settling into their usual pattern, no DHCP, no web UI on the usual address, no ping. Just the power LED and a quiet, expensive sense that I had broken something that had been working an hour ago for no reason at all.
The mistake, in hindsight, was not double-checking the exact hardware revision. These devices get silently revised. Same model number on the box, same case, different flash chip or a different switch inside, and the firmware image for "revision 1" does not necessarily boot on "revision 2". I had grabbed the image for the model, not for the revision, and the bootloader had loaded a kernel that could not talk to the hardware it found itself on.
Serial to the rescue
A device like this is almost never truly dead. The bootloader lives in its own chip and usually survives a botched firmware flash, because you overwrite the OS partition, not the bootloader. The problem is purely that you cannot reach it over the network anymore. You can reach it over serial.
So out came the soldering iron. Most of these boards have an unpopulated header or a row of pads for a UART, three or four contacts: ground, transmit, receive, and a voltage pin you leave well alone. A USB-to-serial adapter at 3.3V logic levels, not 5V, this matters and getting it wrong is how you turn a recoverable brick into scrap.
I tacked three wires onto the pads, connected ground first out of habit, and opened a terminal:
screen /dev/ttyUSB0 115200
Power-cycled the router and the boot log scrolled past. That alone was a relief, because a scrolling boot log means the bootloader is alive and the silicon is fine. The kernel was panicking a second or two in, exactly consistent with a wrong-revision image. The bootloader paused for a moment offering an interrupt prompt, I hammered the key it wanted, and dropped into the bootloader's own little command shell.
Recovery
From there it was the bootloader's built-in recovery path. These vary by vendor, but the shape is the same: point it at a TFTP server, hand it the correct image, let it write that to flash directly, bypassing the broken OS entirely.
# on the laptop
sudo dnsmasq --no-daemon --enable-tftp \
--tftp-root=/srv/tftp --listen-address=192.168.1.10
Then in the bootloader I set the device and server addresses, named the file, and let it pull the image over and flash it. This time I had the correct revision, checked twice, checksum and all. It wrote, it verified, I told it to boot, and the lights came up in their familiar pattern. Working router again, roughly four hours after I had broken a working router.
The reckoning
I got lucky in the only way that mattered: the bootloader survived, and the board had accessible serial pads. Plenty of devices have neither, and on those a wrong flash is genuinely terminal unless you fancy desoldering the flash chip and reprogramming it externally, which is a different and much longer Saturday.
Did the new firmware turn out better? Honestly, marginally. More configurability, updates that actually arrive, a couple of features I wanted. But I would not pretend it was worth the afternoon, and it certainly was not worth the half hour where I genuinely thought I had killed it.
The honest lesson is not "don't flash routers", because I will absolutely do it again. It is the boring one: check the exact hardware revision before you write anything, and know where the serial pads are before you need them, not after. The recovery is only a footnote if you did the reading first. If you did not, it is the whole afternoon.