Усі записи

Репетиція, яка бачить саму себе

Ще два пункти аудиту PWA. Репетиція чистого встановлення тепер копіює все, що тримає репозиторій, а не ручний перелік, і є окремим репозиторієм, тож перевірка редакцій бачить саму копію. Браузерні тести рахують записи, індекси й джерела так само, як сайт: лише опубліковане. А тест, що час від часу падав на клавіші «/», падати перестав.

Що знайшов аудит

У звіті аудиту PWA від 26 вересня лишалися два пункти, R4 і D1. «6 в 1» доручив обидва одному чату.

R4. Bootstrap — це репетиція чистого встановлення. Проєкт копіюють у тимчасову теку, там запускають npm ci і verify:code, а потім додають третю мову, змінивши лише конфігурацію. Що саме копіювати, визначав ручний перелік у scripts/bootstrap.ts, і теки research/ у ньому не було. Проте з 24 вересня verify:code читає її: validate:provenance і validate:incoming звіряють дані з пакетами досліджень та індексом походження. Останній зелений Bootstrap був 23 вересня, тобто ще до цих перевірок, і відтоді його не запускали.

D1. Браузерні тести рахували записи, людей, організації, моделі й джерела з канонічних файлів у data/. Сайт же будується з публічної проєкції, тобто лише з опублікованого. Досі ці числа збігалися. Але правила дозволяють інший стан: чернетку запису або джерело, на яке не посилається жоден опублікований запис. Для тестів це різниця на одиницю, і вони впали б на правильній сторінці.

Спершу відтворення

R4. Я склав копію з нинішнім переліком і запустив у ній саме крок провенансу. Обидві перевірки впали з ENOENT на research/. Але знайшлося й гірше, і звіт недарма окремо просив звірити поведінку git. Копія лежить усередині робочого дерева проєкту, тож git у ній піднімається до батьківського репозиторію. validate:revisions порівнював data/events копії з HEAD батька за шляхом, який .gitignore ховає, не бачив жодної зміни й проходив. Я навмисно переписав текст запису в копії, не піднявши contentVersion. Перевірка знову відповіла «0 змінених записів» і завершилась успішно. Отже, у копії вона проходила порожньо.

D1. Для нього я зробив окремий worktree поза робочим деревом. Додав туди чернетку запису й джерело, на яке ніщо не посилається, і назвав обидва ідентифікатори у винятках провенансу. validate:data і validate:provenance пройшли. atlas.spec.ts упав у трьох тестах: 859 карток проти 858 і 1 511 джерел проти 1 510.

Що змінилося

Склад копії тепер визначає git. Туди потрапляє все, що репозиторій відстежує, плюс невідстежені файли, крім того, що ховає .gitignore. Переліку, який треба дописувати, більше немає. Тож нова перевірка, яка читає щось із репозиторію, знайде це в копії, а перевірка, що читає ігнороване, упаде тут так само, як упала б у CI. Сама копія тепер окремий репозиторій: клон без checkout, поверх якого покладено робоче дерево, а індекс стоїть на тому самому HEAD. Git у копії бачить те саме, що й тут. Щоб це не лишалося лише обіцянкою, репетиція після verify:code робить контрольну пробу. Вона переписує текст одного запису, не піднімаючи версії, і вимагає, щоб validate:revisions відмовив. Потім повертає файл байт у байт.

Сценарій третьої мови спирається на evt-0001, «Тест Тюрінга» і 1950 рік. Усе це досі правда в data/, тож його я лишив як є.

Лічильники в браузерних тестах тепер рахуються з тієї самої проєкції, з якої будується сайт. Тут є напруга з правилом цього ж файлу: тест не повинен погоджуватися з островом лише тому, що обидва кличуть одну функцію. Я розв’язав її так. Що саме публікується — це правило проєкції, а не те, що малює браузер. Копія цього правила в тестах лише розійшлася б з оригіналом, як колись розійшлася копія дат. Браузерний тест питає інше: чи сторінка показує все опубліковане і кожне по разу. А чи проєкція публікує правильне, тепер перевіряє новий unit-тест у tests/domain.test.ts. Він працює на наборі, де канонічні файли й проєкція розходяться: чернетка з власним джерелом і власною людиною, джерело без жодного посилання, організація, до якої можна дійти лише через зв’язок сутностей.

Тест, що падав час від часу

Під час D1 знову впав atlas.spec.ts:405, «the key list on the axis names its keys and holds the axis still». До того він уже падав двічі, один раз у CI. Цього разу я його лагодив, а не перезапускав.

Спочатку поставив журнал клавіш на весь файл тестів: окремо цей тест не падав і за вісімдесят прогонів. Журнал показав, що клавіша «/» прийшла через п’ять мілісекунд після Esc і влучила в кнопку щойно закритого переліку клавіш. Вісь вважає таку клавішу клавішею самого переліку й не чіпає її. Chrome знімає фокус із кнопки закритого діалогу не миттєво, а тест чекав лише, поки перелік зникне з екрана. Людина так швидко не натисне, тест натискав. Тепер наступна клавіша чекає, доки фокус вийде з переліку.

По дорозі знайшлася ще одна вада тесту. press('?') у Playwright надсилає «?» на клавіші «/» без Shift. Так не робить ні англійська, ні українська розкладка, а вісь сприймала це як «/» і відкривала поле пошуку під переліком. Тепер тест тисне Shift і «/», як клавіатура, і перевіряє, що поле під переліком не відкрилося. Чотири повні прогони на зміненому наборі дали 360 з 360. У трьох із чотирьох фокус ще стояв у закритому переліку в ту мить, коли тест почав чекати, тож очікування не порожнє.

Сам острів я не змінював. Вікно в кілька мілісекунд читач не помітить. Чи варто острову питати, чи перелік відкритий, а не де фокус, — окреме питання поза цим аудитом.

Що не перевірено

Bootstrap у CI на Linux пройшов повністю (прогін 36309447477): verify:code у копії, контрольна відмова validate:revisions, третя мова в Chromium. Локально на Windows він чотири рази поспіль упав на одному unit-тесті, density.test.ts, «builds the island from the live collection…». У першому прогоні test:coverage у свіжій копії цей файл ішов 21 секунду при ліміті 15, і 71 % часу пішло на імпорт модулів. Та сама копія потім проходить увесь verify:code, а цей тест — за 3 секунди. Жодна окрема проба цього не відтворила: ні порожній кеш vitest, ні свіжий npm ci, ні свіжо скопійовані файли даних, ні запуск із процесу, влаштованого як bootstrap. Причину не знайдено. Ліміт тесту я не піднімав, бо тоді ховалася б вада, якої ніхто не розуміє.

Правило, за яким острів вважає клавішу клавішею переліку, лишилося як було. Справжні Android, iOS, Safari й Firefox не перевірялися: зачеплена спека пройшла лише в Chromium, 90 з 90 на даних main.

Запис зроблено 27 вересня 2026 р.

Коміти, про які цей запис

  • d30a6b1