fix: SessionStart banner reliability on first session (busy_timeout + adaptive defer)#16
Merged
Merged
Conversation
The 250ms banner defer (so tre-mem renders below claude-mem) wasn't enough on a project's first session: claude-mem's longer first-run onboarding banner is slower to render, so tre-mem raced above it. Make the defer adaptive: 1200ms when claude-mem has no memory for the project yet, 250ms steady-state, 0 on non-Claude harnesses / when claude-mem is absent. TRE_MEM_HOOK_DELAY_MS still overrides everything. Extract the policy into a pure, unit-tested src/hooks/defer.ts (sessionDeferMs); the CLI feeds it the disk/DB probes (claudeMemHasProject via listProjects).
…n SQLITE_BUSY On a project's first (seeding) session the SessionStart hook, the MCP server, and the background web daemon all open ~/.tre-mem/tre-mem.db at once. With no busy_timeout, SQLite returned SQLITE_BUSY instantly: the hook's branch_state write threw → empty envelope → no banner, and the MCP open failed → "1 setup issue: MCP". Set busy_timeout=5000 on every connection (sidecar writer, migrate, and the read-only claude-mem adapter) so they wait out the brief contention. Adds TreMemRepo.busyTimeoutMs() introspection + a regression test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the tre-mem SessionStart banner failing to show on a project's first
session (reported alongside a "1 setup issue: MCP" warning). Two distinct root
causes, both fixed.
1.
SQLITE_BUSYon the seeding first session (the "no banner + MCP issue")On the first session of a project, three short-lived
treprocesses open~/.tre-mem/tre-mem.dbat the same time: the SessionStart hook (migrate+branch_statewrite), the MCP server, and the autostarted web daemon (WALcheckpoint). The sidecar DB opened with no
busy_timeout, so SQLite returnedSQLITE_BUSYinstantly instead of waiting:Fix: set
busy_timeout = 5000on every connection (sidecar writer,migrate,and the read-only claude-mem adapter). Proven directly: a write under a held lock
throws in
0 mswithbusy_timeout=0vs waiting~339 mswith300.2. Banner ordering on the no-memory first session
The defer that makes tre-mem render below claude-mem was a fixed 250 ms — too
short for claude-mem's slower first-run onboarding banner, so tre-mem raced above
it. Now adaptive: 1200 ms on the first session, 250 ms once a project has
claude-mem memory, 0 on non-Claude harnesses / when claude-mem is absent.
TRE_MEM_HOOK_DELAY_MSoverrides everything.Changes
src/store/paths.ts—DB_BUSY_TIMEOUT_MS = 5000src/store/repo.ts,src/store/migrate.ts,src/adapter/claude-mem.ts—apply the pragma;
TreMemRepo.busyTimeoutMs()introspection accessorsrc/hooks/defer.ts— pure, unit-testedsessionDeferMs(adaptive defer)src/cli.ts— feed disk/DB probes intosessionDeferMs;claudeMemHasProjectCHANGELOG.md— Unreleased entryTest plan
test/hook-defer.test.ts(6) +test/repo.test.tsbusy_timeout regressionformat:check,lint,typecheck, 403 tests,buildonego-ios): hook fired under a held lock nowwaits and emits the banner; direct write-under-lock proof confirms the
SQLITE_BUSYmechanism