medlab / case

medlab

what got hurt, and what now fails loudly

↑ sublayer

2026-10-14 · fixed: yes

A migration transaction also locks SQLite connection setup

RuntimeIntegration Tests

now fails loudly A test holds the initialization lock and asserts that a second initializer cannot create the database before the lock is released.

What broke

An API process and a worker initialized the same SQLite database. Both enabled WAL mode before starting the transaction that serialized migrations. The transaction protected the migration statements, but not the preceding journal-mode change.

How it showed

A concurrent initialization test failed with sqlite3.OperationalError: database is locked. The stack trace pointed to PRAGMA journal_mode=WAL. The same two-thread test had passed in an earlier run.

What was watching

Formatting and lint checks passed because they did not exercise database locking. A startup test opened the application sequentially and also passed. The concurrent integration test detected the race during implementation, before the affected revision was deployed.

Where it sits

This is a runtime failure in the scope of mutual exclusion. The integration-test sensor was present and fired against real SQLite connections. Its first passing execution did not prove that all startup operations were serialized.

What we did

A process lock now covers initialization before any SQLite connection is opened. The migration transaction remains inside that lock. The fix also adds a test that holds the outer lock while starting another initializer.

What now fails loudly

The new test asserts that the second initializer remains blocked and has not created a database file. It then releases the lock and requires initialization to finish. Replacing the application's process lock with a no-op caused the test to fail because initialization returned before the expected timeout. The restored implementation passed the test and the full application suite.