⌂ все дашборды/Качество и аудиты← Twins-Audit-20260809 · Vault-Audit-2026-07-07 →
Пустая строка вместо NULL

Пустая строка вместо NULL — что чинили в ночь на 20 августа

Хаб A-2022BAYAREA · база E:\Obsidian\_imports\leads.db · цифры сняты с живой базы и с бэкапа 13:58 pre-vcround-null-fix

Главное: насколько врал прибор

81 537строк в vc_round
81 537читатель с IS NOT NULL считал заполненными — было, это 100%
8 062реально пригодны для анализа (9.9%) — столько же он видит сейчас
73 475 → 0строк, про которые прибор врал
Одной картинкой
было: «данные есть» на всю таблицу
стало: «данные есть» ровно там, где они есть

Писателей у vc_* было четыре, а починили три

СкриптЧто писалКогда починен
build_vc_graph.pyf.get(key, '') на пустых полях Airtable19.08 днём, дневная сессия
build_vc_graph2.pyлитеральные '' в ins_round (forms-rounds, signal)19.08 днём, дневная сессия
build_vc_graph3.pyлитеральные '' для архивных раундов19.08 днём, дневная сессия
warm_tw_bridge.pySET tg_handle='', tg_src='' — чистка своих прошлых вставок, рутина 04:1519.08 ночью, эта сессия
Почему четвёртый важнее самой находки. Дневная починка была правильной и по корню. Но обход писателей шёл по имени роли — искали скрипты build_*, — а не по факту записи в таблицу. Четвёртый писатель это отдельная ночная рутина «VC Nightly Warm Refresh» в 04:15: она вернула бы 2 452 пустых ячейки примерно через четыре часа после того, как починку объявили закрытой. Контрфакт на копии 500 строк: старый SQL даёт 500 пустых ячеек, новый — 0. Живой прогон патченого скрипта: 1,2 с, 2 452 привязки на месте, реальные хендлы (2 614 и 5 847) целы, пустых ячеек 0.

⛔ Что сознательно не тронуто

Та же болезнь шире: 9 495 340 пустых ячеек в 8 таблицах, у них 16 живых писателей. Трогать их сегодня нельзя — там '' местами несёт смысл: leads.last_contact='' означает «ни разу не контактировали» (5 469 строк), и alpha/leadsignal_scan.py отбирает дормантных инвесторов ровно по last_contact = ''. Замена на NULL молча выкинула бы эти строки из сигнала. Сначала разбор писателей и читателей, потом данные.
Таблицастрокпустых ячеекхудшие колонкиписатели
airtable_records907 4565 154 361handle 893 754 · email 876 936 · role 867 065fold_delta.py · load_airtable_to_db.py
archive_contacts312 2542 001 169company 300 376 · phone 299 929 · email 236 475gdrive/wire_archive_contacts.py
people292 5101 462 368vault_slug 283 213 · category 280 040 · status 280 039build_unified_sql.py · dedup_people.py · dialogs/match_members_to_crm.py · fb_audience.py
companies88 549470 333location 88 441 · linkedin 88 245 · telegram 85 322build_unified_sql.py
contacts80 789247 409org 77 254 · person_note 76 370 · relationship 76 370apple-contacts/build_contacts_db.py · browser-history/contacts_to_db.py · build_leads_db.py · gdrive/gold_extract.py
vc_contact_match123 402115 811note 115 811build_warm_matches.py
leads14 13536 177country 7 450 · crm_tg_id 5 995 · first_contact 5 470build_leads_db.py · crm-engine/drip.py · listener.py · retag.py · retag_v2.py
works_at36 8097 712role 7 712build_unified_sql.py

Что теперь сторожит

E:\Obsidian\_imports\_test_sql_hygiene.py — три проверки, ноль LLM, ноль сети:красный тест пройден подложенный старый писатель ловится, выход 1.  панель ломателей три семьи моделей через OpenRouter, все возражения проверены по коду и закрыты.
Честная граница сторожа: живая проверка покрывает только vc_*. Восемь таблиц выше он не сторожит — там сначала нужен разбор писателей.
Собрано автоматически 19.08.2026 23:46 · бэкапы: _backups\leads.db.pre-warmbridge-nullfix-20260819 (1,33 ГБ), _backups\warm_tw_bridge.py.bak-20260819-233805