Repository navigation
Description
Several test files build their project directly under the system temp dir. test/test_tui.py's temp_project_dir fixture, for one, creates it with tempfile.TemporaryDirectory() and builds a CacheManager without a db_path. CacheManager then defaults to get_cache_db_path(project_path.parent). That is <tmp>/claude-code-log-cache.db, one file that every such test, every run and every checkout on the machine shares.
What goes wrong
The shared database outlives the tests and takes whichever schema the last code to open it migrated it to. When a checkout carrying a later migration runs these tests, an older checkout's run then fails on schema it does not know.
This happened on 2026-11-07. A checkout of #390, which adds 016_drop_refresh_pending.sql, opened /tmp/claude-code-log-cache.db and migrated it to 016 at 03:26Z. From then on, main's code (migrations up to 015) failed 24 of test_tui.py's 63 tests, all with:
sqlite3.OperationalError: no such column: refresh_pending
They fail in SessionBrowser.on_mount → load_sessions → CacheManager.get_modified_files. Nothing in the tree under test was wrong. The same tests pass once the temp dir is fresh:
# main's code (88426a39), default temp dir
uv run pytest test/test_tui.py -n0 -p no:cacheprovider -q -m "tui or not tui"
→ 24 failed, 39 passed
# the same tree, a fresh temp dir
TMPDIR=$(mktemp -d -p ~/tmp) uv run pytest test/test_tui.py -n0 -p no:cacheprovider -q -m "tui or not tui"
→ 63 passed
The same stale database also fails just test on main's code: 13 tests in test/test_pagination.py and test_multi_session_rendering in test/test_template_rendering.py, all with IndexError: No item with that key on project_row["refresh_pending"] (CacheManager.get_cached_project_data). In a fresh temp dir the two files pass in full (49 and 11).
A fresh temp dir is not enough under xdist. just test-tui runs with pytest-xdist's default -n auto. With TMPDIR set to an empty directory, every worker's temp projects share one brand-new $TMPDIR/claude-code-log-cache.db, and several workers run its migrations at the same moment. One run gave 4 failures out of 71, all raised in migrations/runner.py's run_migrations from CacheManager.__init__:
sqlite3.IntegrityError: UNIQUE constraint failed: _schema_version.version (3x)
sqlite3.OperationalError: duplicate column name: combined_linked (1x)
Migrating that database once first (one test with -n0) and then running the suite against the same TMPDIR gave 4129 passed, 7 skipped for just test. A first run on a fresh CI runner could hit the same race; CI history has not been checked for it.
The shared file also accumulates: it held 1,423 project rows, all /tmp/tmpXXXXXXXX paths, read with SELECT count(*) FROM projects in read-only mode.
Scope
- Verified:
test/test_tui.py(24 failures on the stale database, 4 from the migration race on a fresh one),test/test_pagination.py(13) andtest/test_template_rendering.py(1). - Not checked: whether other tests do the same. These test files create temp dirs with
tempfile.TemporaryDirectory()ormkdtemp(), and any of them that builds aCacheManageror runs a conversion withoutCLAUDE_CODE_LOG_CACHE_PATHor adb_pathwould share the same file:test_cache.py,test_tui_expansion.py,test_integration_realistic.py,test_session_scan_characterization.py,test_template_data.py,test_sidechain_agents.py,test_lanes.py,test_project_matching.py,test_combined_transcript_link.py,test_image_paste_ids.py,test_memory_browser.py,test_todowrite_rendering.py,test_webfetch_rendering.py, and the browser filestest_query_params_browser.py,test_timeline_browser.py,test_search_browser.py. - The stale-schema failure needs a temp dir that outlives a run, so it bites on a developer machine that runs several checkouts, or a branch carrying a new migration, over the same temp dir. The migration race needs only a fresh temp dir and xdist.
Possible fix
test/conftest.py already has isolated_cache_dir / isolated_db_path / isolated_cache_manager, described there as preferred over the older temp_project_dir pattern. Two ways to use that:
- Move
temp_project_dirontotmp_pathand give the cache an explicit path inside it. - Have an autouse fixture set
CLAUDE_CODE_LOG_CACHE_PATHto a per-test path for every test that does not set its own. That would also cover the files above without touching each one.
🤖 Generated with Claude Code
Activity