#329

fix: wait out SQLite busy on concurrent asset upserts

OpenOrdinarySFwants to merge intofrom

Summary

Fixes #328

Deep mode fires many create_asset calls in the same turn. Those writes hit SQLite database is locked in 4–26ms, so _busy_timeout=5000 never actually waited.

This is not a missing pool. configureDBPool already sets MaxOpenConns=25. SQLite still allows only one writer. UpsertAssets uses a DEFERRED transaction (SELECT then INSERT). Parallel deferred txs deadlock on the write upgrade and SQLite returns SQLITE_BUSY immediately.

Changes

  • Open SQLite with _txlock=immediate and _busy_timeout=30000
  • Drop the pool from 25/5 to 8/4 (WAL still has concurrent readers; 25 write connections made lock storms worse)
  • Retry UpsertAssets a few times on database is locked
  • Shared sqliteOpenDSN() for conversations and knowledge DBs

Test plan

  • TestUpsertAssetsConcurrentDoesNotReturnLocked — 32 goroutines upsert distinct hosts
  • go test ./internal/database -run 'Asset|Upsert'
  • Existing asset tests still pass