fix(etl): detect wrangler's SQLITE errors from stdout in safeD1 - #277
Conversation
|
Чист split — двата реда нямат нищо общо с индекса на качеството и логично вървят отделно (авторството на @StanislavBG е запазено в комита). Поправката е коректна: wrangler пише SQLITE грешката в stdout, не в Ортогонално на #270 (не е зависимост по ред на merge): probe-ът върху |
safeD1 tested err.message for "no such table", but wrangler prints the SQLite error as JSON on stdout and leaves the exception message as a bare "Command failed: wrangler d1 execute ...". The guard therefore never matched, safeD1 rethrew instead of returning [], and the data_freshness fallback in latestLoadedDate was unreachable. The visible effect is that `pnpm run import --catchup --plan-only` crashes whenever the transient staging tables are absent, which is their normal steady state: drop-transient-staging removes them in a finally, and --plan-only exits before the main flow recreates them. Ordinary runs are unaffected, since they create an empty raw_contracts first and so reach the fallback. Cherry-picked verbatim from e3fc6b3 in #188 by Bilko (StanislavBG), split out so the fix can land without the contract health index feature.
fdc7169 to
872953a
Compare
Test coverage
✅ No workspace dropped below its baseline (tolerance 0.5pp). 📈 Coverage rose by more than 1pp — run |
|
Кодът тук е на @StanislavBG - двата реда идват дословно от #188 и коммитът в клона беше негов. При squash обаче GitHub записа автор мен, не него: Това е моя грешка в преценката. Смятах, че щом PR-ът е с един-единствен коммит, авторството оцелява при squash - не оцелява. Авторът на PR-а печели винаги, независимо от броя коммити. Единственото, което пази заслугата, е мърджване през PR, отворен от самия автор; трябваше да върна поправката в неговия PR, а не да я вадя в свой. Заслугата за поправката е негова. Записвам го и тук, и в бележките към изданието, понеже пренаписване на Отделно: обяснението в описанието, че тест няма как да се направи, вече не важи - #270 донесе |
Поправката от #277 нямаше нищо, което да я пази: `import.mjs` изпълнява код при внасяне, тъй че `safeD1` не се тества модулно. Сглобката от #270 обаче кара истинския скрипт като отделен процес с подставен `wrangler`, и това е достатъчно. Подставката е сверена срещу истинския двоичен файл, а не измислена - при `d1 execute --json` върху липсваща таблица грешката от SQLite излиза на stdout, известията на stderr, а съобщението на изключението е само „Command failed". Точно това разминаване изпускаше старата проверка. Наблюдаваният изход е записан в теста. Мутациите: връщането на проверката само върху `err.message` вали два теста, а превръщането на safeD1 в общ капан вали третия.
Изваден от #188 на @StanislavBG. Кодът е негов, дословно, и коммитът пази авторството му, тъй че при squash заслугата остава при него.
Защо отделно
#188 („индекс на качеството на договорите") е голям feature PR - миграции, derive стъпки, две нови страници, 40+ коммита. Тази поправка е случайно попаднала вътре: два реда в
scripts/import.mjs, които нямат нищо общо с индекса на качеството. Ако остане там, тръгва чак когато цялата функционалност мине ревю, а дотогава--plan-onlyстои счупен. Затова я разделяме - поправката да върви със своя скорост, а #188 да се преглежда по същество.Няма нужда @StanislavBG да прави нещо. Когато това се слее, хънкът в #188 или ще се разреши сам при rebase, или ще е тривиален конфликт с еднакъв резултат.
Проблемът
safeD1търсеше „no such table" вerr.message. Но wrangler печата грешката от SQLite като JSON на stdout, а изключението остава голоCommand failed: wrangler d1 execute .... Проверката така никога не хващаше,safeD1пре-хвърляше вместо да върне[], и fallback-ът къмdata_freshnessвlatestLoadedDateбеше недостижим.Видимият ефект:
pnpm run import --catchup --plan-onlyгърми, когато transient staging таблиците ги няма - а това е нормалното им състояние, понежеdrop-transient-stagingги маха вfinally, а--plan-onlyизлиза преди основният поток да ги пресъздаде. Обикновените пускания не са засегнати: те първо създават празенraw_contractsи стигат до fallback-а.Проверка
Срещу истинска локална база, след като transient staging таблиците са махнати (тоест в нормалното steady-state състояние):
Преди -
--plan-onlyгърми:След - fallback-ът работи и планът се отпечатва, exit 0:
prettier --checkе чист.За теста
Първата редакция тук казваше, че тест няма как да се направи:
import.mjsизпълнява код при внасяне, тъй чеsafeD1не се тества модулно. Това вече не е вярно - #270 донесеscripts/import-guard.test.mjs, който кара истинскияimport.mjsкато отделен процес с подставенwranglerнай-отпред в PATH. Същата сглобка става и тук.Тестът обаче нарочно не влиза в този PR: коммитът е един и е на @StanislavBG, тъй че при squash заслугата остава при него. Втори коммит от мен би я прехвърлил. Тестът идва с отделен PR.
Затова поправката е проверена с изпълнение, в двете посоки, със същата сглобка. Подставеният
wranglerвръща грешката така, както я връща истинският - JSON на stdout, голо съобщение на изключението:Без поправката
--catchup --plan-onlyгърми:С поправката fallback-ът към
data_freshnessсе достига и планът се отпечатва:Клонът е пребазиран върху
main(а не слят), за да остане един коммит и авторството да се запази при squash.