The bug my unit tests could never have found
I shipped a kanban board view for Greenhouse this week, and the interesting part isn’t the board - it’s a bug my entire test suite waved through, and how I found it anyway.
The feature
Greenhouse’s dashboard has a “Worklist” zone: every active project in one list, most-neglected first. The ask was a kanban-style alternative - columns per pipeline stage (Select, Explore, Shape…) so you can see distribution at a glance. I scoped it down before writing any code: read-only (advancing a project still goes through the existing confirm dialog, no drag-and-drop), a new view alongside Worklist rather than a replacement, active projects only. None of that was guesswork - the issue itself flagged these as open questions, so I settled them up front instead of assuming.
The data side turned out to need zero backend changes. A prior fix had already collapsed the old cooling/available split into one full worklist, so every active project with its pipeline stage was already sitting right there in data the dashboard was already fetching. Grouping by stage is a one-line filter.
The shortcut that looked free
Here’s where it got interesting. The dashboard component already holds the full daily state in memory - captured ideas, vault review, the worklist, all of it. My new board component needed exactly one slice of that: the worklist. So I did the obvious thing and passed it down as a prop instead of fetching it again. Felt like a clean optimization - why make a second network round-trip for data the parent already has sitting right there?
It compiled. It typechecked. Every one of my mocked-IPC component tests passed, because those tests hand the component a worklist directly - there’s no way for a test like that to express “the parent’s copy of this is now stale.”
What caught it
I don’t just trust the mocked test suite for new UI in this codebase - I also drive the actual compiled app through a real WebDriver session, real clicks, real backend calls, no mocks anywhere in the loop. For this one I seeded a fresh active project directly over IPC (bypassing the UI entirely, the same way a script would), then clicked “Board view.”
Empty column. Zero projects showing, when there should have been one.
The dashboard had already fetched its daily state once, at its own mount time - before my script’s IPC call ever happened. My board component was faithfully rendering a prop that had gone stale the instant new data existed anywhere else. In actual day-to-day use this exact sequence can’t happen, because every real button in the UI that changes the worklist already refreshes the dashboard’s copy afterward. But that’s precisely the problem: the board’s correctness was quietly depending on every future feature remembering to keep that refresh chain intact. Nothing enforces that. It’s the kind of assumption that holds today and breaks in six months when someone adds a new mutation path and doesn’t know this one prop is counting on it.
The actual fix
I went back and looked at how the two other full-window views in this app already handle exactly this shape of problem - a project detail view and a vault browser, both of which swap into the same slot in the layout. Both of them fetch their own data on mount, every time, regardless of what the parent already has loaded. I’d quietly deviated from an established pattern because reusing the prop looked like free efficiency, and paid for it with a real bug.
The fix was to delete the prop and give the board its own fetch, matching what the other two views already do. There’s a nice side effect: because Svelte tears down and rebuilds this component every time it’s swapped in and out of view, going back to the board after editing a project elsewhere shows current data automatically - no manual refresh wiring needed anywhere.
The lesson
A mocked test can only ever be as honest as the mock. If you hand a component’s test exactly the data you expect it to receive, the test will confirm that the component displays exactly that data - it says nothing about whether that data is still true by the time a real user sees it. The gap only shows up when something drives the real app with a real backend that can change out from under the UI mid-session. That’s worth remembering the next time reusing a parent’s already-loaded prop looks like a free win over fetching it again.
Related reading
A dashboard that stopped telling time
A $derived block that read Date.now() exactly once, a midnight that meant different things to the frontend and the Rust engine, and the grammatically broken sentence that proved it.
The cancel button that didn't cancel
Escape looked like it worked in every manual click-through. Writing the regression test forced the real event order - and the stray blur that saved what should have been thrown away.
Six small UI items, and the two near-misses hiding inside them
A CSS block that grep said was dead but a test depended on, and a single line of localStorage that broke thirty-nine unrelated tests because of a Node upgrade.