По требованию пользователя «не сохранять всё подряд, а только то, что
нужно для эволюции»: рядовые геномы поколения больше НЕ пишутся строками
в runs — писатель получает лёгкие StatsOnly-инкременты (счётчики,
гистограмма, причины отказов на дашборде остаются честными по ВСЕМ
оценкам), а полная строка пишется только когда лучший геном острова
улучшился (+ полировка). Вставка миллионов строк в HDD-базу с 6 индексами
была узким местом конвейера: GPU считал цикл ~23 мин, дозапись хвоста
очереди шла часами (~150 строк/с), реальная скорость была ~165 оценок/с
вместо ~1300/с. gpu_record_worker стал не нужен — удалён.
Выборка эволюции уменьшена до 10000 на поколение (8 островов x 1250,
было 8x4000=32000) — по просьбе пользователя, чтобы поколения сменялись
быстрее; поколений за цикл теперь 120 (было 60) — при освобождённом
писателе цикл углубляется вдвое дальше за то же время.
- storage/schema.py: `runs` table recording every evaluated configuration,
feasible or not, with an honest infeasible_reason instead of dropping
failures
- storage/database.py: WAL-mode SQLite, single-writer-over-a-queue pattern
for safe concurrent writes from many sweep worker processes
- Testing with real multiprocessing.Process (not mocks) caught a genuine
bug: a duplicate run_id raised inside the writer loop and killed the
writer process, silently halting queue drainage for the rest of a
sweep. Fixed by catching the insert error per-record and logging to
stderr instead of crashing; added a regression test for it.
- Verified locally and inside the Docker image (43/43 tests both ways)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>