One hard interaction
ยท Open
The interaction this page is meant to cover is runlog's virtualised trace list: 50,000 events, scrollable, without the page falling over.
Not written yet, waiting on P-5
The virtualised trace list in runlog. There is no shipped code for runlog, so there is no implementation to write up, no measurements to report and no scroll behaviour to describe honestly.
Checked 2026-09-21.
The hard interaction that is shipped
Since the brief asks for one hard interaction with its write-up and the intended one does not exist, here is the one that does.
Cancelling a query that cannot be interrupted
SQLpad runs real SQL against dropped CSV files using sql.js, which is SQLite compiled to WebAssembly. A badly shaped join across two files will run for a long time, and sql.js offers no interrupt: once exec is running, that thread is gone until it finishes.
The usual answer is a spinner and a lie. The button says cancel, it sets a flag, and the query finishes anyway.
The design. The database lives in a Web Worker and nowhere else. The main thread holds the parsed tables. Cancelling terminates the worker, spawns a new one, and replays the same tables into it from the copy the main thread still has.
main thread worker
----------- ------
tables (parsed CSV) ---load---> CREATE TABLE, INSERT
---query---> db.exec(sql)
[user hits cancel]
worker.terminate() (gone mid-statement)
spawn new worker
tables ---load---> CREATE TABLE, INSERT
Why the main thread keeps the tables. Without that copy, the only place the data existed would be inside the thread that just had to be killed, and cancel would mean losing the dataset. Holding it twice costs memory; not holding it costs the feature.
What it costs. Rebuilding the tables after a cancel is not free: on a large drop there is a visible pause while the inserts replay. That is the honest trade, and the app says "the tables were rebuilt and are ready again" rather than pretending the cancel was instant.
What is still wrong with it. Every pending promise on the terminated worker is rejected with the same cancellation error, so a second query queued behind the first is cancelled too. In practice nobody queues a second query behind one they are actively cancelling, but it is not correct, and correct would mean tracking which promises were in flight rather than clearing the map.
The implementation is src/lib/engine.ts and src/workers/sql.worker.ts in the sqlpad repo.