Эволюция продукта

Что проверено, когда и с каким исходом. Зелёное здесь означает «проверено недавно и сошлось»: результат старше полутора суток отмечается как неизвестный, потому что доска, показывающая вчерашнее за нынешнее, хуже отсутствующей.

Последние прогоны

Прод

есть находки

Проверок прогнано 14, с находками 4. Заняло 336.6 с.

· версия 0.16.0-alpha

Что система умеет проверять

Всего проверок 65, из них 9 умеет прогнать само приложение — они и попадают в ночной прогон. Остальные запускаются командой и здесь перечислены, чтобы было видно не только что проверено, но и что нет. Рядом с ними 6 отчёта: они читаются глазами и помечены отдельно.

База и выкладка

ПроверкаЧто сверяетКомандаСостояние
Осмотр перед запускомОтвечает ли база, нет ли в журнале отметки dev, долгих транзакций, раздутых таблиц и непроверенных ограничений. Сверку журнала со схемой осмотр обещал, но не делал — она в migrate:baseline и стоит десятков запросовdoctorПрод
Присмотр за пулом соединенийУ обрыва соединения ровно один слушатель: без него обрыв убивает процесс, а лишние пишут в лог по копии на каждыйcheck:poolещё не гонялась
Куда уходит время самой медленной страницыКаждый шаг сборки данных замеряется отдельно, и рядом — тот же шаг дешевле. Без разложения починку кладут туда, где правдоподобно, а не туда, где секундыaudit:slowотчёт: читается глазами, упасть не может
Индексы против запросовКакие индексы не используются и каких не хватает под настоящую нагрузку. Порога «допустимо» у этого нет: решение об удалении индекса принимает человек, а ревизия даёт ему счёт и готовые командыaudit:indexesотчёт: читается глазами, упасть не может
Следствия записи наступают после коммита, а не внутри негоЖурнал правок, снимки оценок и пересчёт индекса обещают, что их отказ не отменит саму запись. Пока они шли в одной транзакции с ней, обещание было невыполнимо: упавший запрос делает транзакцию неспособной к коммиту, и вместе со следствием откатывалась запись. Проверяется попыткой: до коммита работа не выполняется, после — выполняется ровно раз, после отката — никогдаcheck:after-commitещё не гонялась
Границы в базе и границы в форме — одни и те жеОграничение базы разрешает жирность до пятнадцати процентов, а поле формы не разрешало ничего: границ у него не было вовсе. Человек вводил двести, нажимал «Сохранить» и получал вместо понятного отказа сырое имя ограниченияcheck:boundsещё не гонялась
Схема базы совпадает с ожиданиями PayloadПоле, добавленное в коллекцию без миграции, ломает запись молча: типы переписаны, а колонки в базе нет. Требует PAYLOAD_DB_PUSH=false — при включённом push Payload устраняет расхождение до того, как проверка его измеритcheck:schemaгоняется вручную

Данные книги

ПроверкаЧто сверяетКомандаСостояние
Отчёты по стаду считаютсяСемь запросов выполняются на живой базе и возвращают то, что обещает типcheck:herdПрод
Списки сходятся с числамиЧисло в отчёте равно длине списка за ним: несходящееся число хуже ошибки — оно правдоподобно с обеих сторонcheck:drilldownПрод
Сервис-период на экране и в реестре — одно числоОтчёт по стаду и выгрузка во ФГИАС ПР считают сервис-период на одних животных и обязаны сойтись день в день: разными они были полгода — на экране дни до первого осеменения, в реестре до плодотворного, и оба под одним именемcheck:service-periodгоняется вручную
Проставленные значения ловятся, а не только объявленыПравило смотрит на форму распределения жира в контрольном дне и состоит из двух половин, которые ломаются по-разному: арифметика — от правки формулы, запрос — от переименованной колонки. Прогон проверяет обе, потому что зелёная арифметика при неработающем запросе выглядит точно так же, как исправное правилоcheck:stampedещё не гонялась
Возраст первого отёла — одно число на четырёх экранахОтчёт хозяйства, сводка Ассоциации, карточка быка и отчёт по производителям считают возраст первого отёла разными запросами и обязаны сойтись с перебором документов: до общего куска SQL один бык показывал на четырёх страницах четыре разных числаcheck:afcгоняется вручную
Ассоциация и хозяйство видят одно и то жеСводка по стадам считается группировкой по всем хозяйствам, кабинет — по одному; разойдись они, Ассоциация позвонит про беду, которой хозяйство у себя не видитcheck:conditionещё не гонялась
Ревизия зоотехнических правилВсе правила реестра прогоняются по настоящим данным: какие срабатывают, какие молчатaudit:checksПрод
Родословная без противоречийЦиклы в родословной, родители моложе потомков, животное само себе родитель, невозможный возраст родителя — по тем же порогам, что видит экспертaudit:pedigreeПрод
Подбор пар считается верноИнбридинг сверяется на случаях с известным ответом: полусибсы, полные сибсы, отец с дочерьюcheck:matingпишет в базу — гоняется только на копии
Сравнение быков со сверстницамиРазница по дочерям считается на построенном контрольном стадеcheck:bullsпишет в базу — гоняется только на копии
Приплод сходится сам с собойТип рождения, числа живых и мертворождённых и карточки телят — на выдуманных отёлах, без базыcheck:calvingгоняется вручную
Рейтинг не врёт местамиРазряды не пересекаются, порядок не возрастает, совпадения делят место, а отбор по хозяйству мест не сдвигаетcheck:rankingгоняется вручную
Разброс признака: заявленный против измеренногоИндекс делит отклонение каждого признака на его стандартное отклонение, и числа σ у нас заимствованные; у смертности приплода подставлено отклонение живучести коров — то есть измеренное на других животных. Спорить, какое чужое число взять, бессмысленно: разброс оценок в своей книге считается, и прогон его считает. Он ничего не правит и не падает — замена σ меняет порядок всех животных в рейтингеcheck:trait-sdгоняется вручную
Выбытие без даты выбытия и цена этой дырыОтчёты о выбытии считают по дате, а не по состоянию, а дату ставили не все дороги ввода: перемещение и событие ленты ставили, поле «Состояние» в карточке и загрузка файлом — нет. Такое животное уходит из знаменателя и не попадает в числитель, то есть занижает долю выбытия дважды и молча. Прогон считает, скольких это касается и на сколько врёт отчёт: рядом с нынешней долей встаёт верхняя оценка настоящейcheck:disposal-dateещё не гонялась
Возрастная группа против факта отёлаСколько записей стоят не в своей возрастной группе и сколько поднимет пересчёт — счёт по живой книге, без порога «допустимо»check:cowотчёт: читается глазами, упасть не может

Доступ и роли

ПроверкаЧто сверяетКомандаСостояние
Чужое закрытоПопытки поднять себе роль и прочитать чужие записи отклоняютсяcheck:securityпишет в базу — гоняется только на копии
Уровень достоверности выводится, а не ставитсяПротокол лаборатории поднимает вторую ступень, отзыв её снимает, а подпись Ассоциации ни то ни другое не трогает. Отдельно — ступень «Отклонено»: она ставится поверх подписи, протокол её не снимает, а новая заявка снимает и возвращает ту ступень, которая следует из книгиcheck:trustпишет в базу — гоняется только на копии
Роли, приглашения, блокировкаСотрудник видит своё, приглашение работает один раз, заблокированный не входитcheck:teamпишет в базу — гоняется только на копии
Границы хозяйствОт лица настоящего пользователя: не видно и не правится ничего чужогоaudit:tenancyпишет в базу — гоняется только на копии
Точечные доступыВыданный доступ открывает ровно одну запись и отзываетсяaudit:grantsпишет в базу — гоняется только на копии
Заслон подтвержденияПоказывает очередь заявок и то, что заслон сказал бы по каждой: какие находки держат подтверждение и чего в данных не хватаетaudit:gateотчёт: читается глазами, упасть не может
Журнал переживает предметЗапись об операции остаётся после удаления того, о чём онаcheck:journalпишет в базу — гоняется только на копии
Сохраняемые отборыОтбор сохраняется, открывается и удаляется, чужой не виденcheck:searchesпишет в базу — гоняется только на копии

Обмен и файлы

ПроверкаЧто сверяетКомандаСостояние
Выгрузка и загрузка книги ExcelНастоящее стадо выгружается, читается обратно и сходится с исходнымcheck:xlsxпишет в базу — гоняется только на копии
Выгрузка во ФГИАС ПРШапка сходится с настоящим шаблоном, наш ключ не выдаётся за номер реестраcheck:fgias-exportгоняется вручную
У пород есть коды ICARБез трёхбуквенного кода порода не уезжает в обмен вовсе, а международный номер собирается коротким: шестнадцать символов вместо девятнадцатиcheck:breed-codesгоняется вручную
Международный номер собирается и разбирается верноНастоящие номера из чешских списков быков разбираются; импортное животное считается от страны происхождения; длинный номер не обрезаетсяcheck:aiidгоняется вручную
Ресурсы ICAR ADE собираются по спецификацииИмена полей и значения перечислений из стандарта, время в UTC, показатель молока строкой, ноль не выдан за «неизвестно»check:adeгоняется вручную
Кодировки и разделители CSVwindows-1251 и UTF-8, точка с запятой и запятая, круговой прогон разбора и сборкиcheck:csvПрод
Смена владельцаЖивотное переходит с историей, прежний владелец теряет доступcheck:movementsпишет в базу — гоняется только на копии
Описание API полноеВсе ручки попадают в OpenAPI: описание, разошедшееся с кодом, хуже отсутствующегоcheck:openapiПрод
Фильтры выборки называются именами стандартаФильтр со своим именем работает и при этом бесполезен: клиент шлёт meta-modified-from, мы ждём своё — и партнёр получает всю книгу вместо изменённого за сутки, без единой ошибкиcheck:ade-filtersгоняется вручную
Каталог пород собран из справочниковКод породы, сопоставленный на глаз, уезжает в международный номер животного и объявляет чужой стране чужую породу; состояние «книга ведётся» обязано следовать из действующей книги, а не из галочкиcheck:breedsгоняется вручную
Лента изменений: метки и опознание удалённогоИдентификатор надгробия, разошедшийся с тем, под которым ресурс уезжал, — это удаление, которого партнёр не заметит: у него всё сойдётся, а корова, которой нет, продолжит доитьсяcheck:ade-genericгоняется вручную
Обмен отвечает по сети так, как обещаноМежду разобранным фильтром и полученными данными лежит слой, который не видит ни одна проверка кода: маршрут, схема локации в адресе, заголовки, коды отказов. Ошибка в нём выглядит как пустой ответ — неотличимо от «данных нет»check:ade-liveнужен обход снаружи — место в ночном действии
Отдаваемое сверяется с настоящими схемами ICARСвоя копия перечислений не поймает изменения стандарта: и проверяемое, и проверяющее написаны одной рукой. Здесь проверяющее написано ICARcheck:ade-schemaгоняется вручную
Приём по ICAR ADE разбирает данные верноСвоя выгрузка обязана проходить свой же приём, а «3,5» вместо 3.5 — отвергаться: принятая запятая даёт тридцать пять процентов жираcheck:ade-acceptгоняется вручную
Готовность книги к выгрузке в реестрРеестр отвергает запись целиком из-за одного незаполненного поля; отчёт считает, сколько животных уедет, а сколько вернётся, и по какой колонкеcheck:fgias-readinessотчёт: читается глазами, упасть не может
Разбор чисел и дат из чужой таблицы«5.03.2026» разбирается прекрасно — во второе марта; проверка утверждает сами значения, а не то, что файл загрузилсяcheck:import-valuesгоняется вручную
Загрузка чужих форматов, файл за файломКодировка, разделитель и разбор значений проверяются по отдельности; здесь настоящий файл проходит весь путь целиком — и печатается, где загрузка портит данные молчаcheck:import-formatsотчёт: читается глазами, упасть не может

Страницы и ссылки

ПроверкаЧто сверяетКомандаСостояние
Соответствие подтверждается, а не заявляетсяКаждое доказательство на странице соответствия ведёт на существующий прогон, файл или адрес; у «выполнено» и «частично» доказательство обязательноcheck:complianceгоняется вручную
Домены разводятся верноВитрина и книга живут на разных доменах одного приложения; ошибка тут не падает, а показывает не то — рекламу вместо кабинетаcheck:hostsгоняется вручную
Принадлежность книги отделена от системыИмя, адрес, телефон и почта организации берутся из настройки книги, а не вписаны в страницы; иначе показательная книга покажет чужие реквизиты, и заметить это можно только открыв еёcheck:tenantгоняется вручную
Ссылки не вложены друг в другаВложенные <a> недопустимы по HTML: браузер перестроит разметку по-своему, и жалоба придёт на гидратацию, а не на причинуcheck:linksгоняется вручную
Обход всех страницКаждая страница живого сервера отвечает, битых ссылок и переадресаций нетsmokeпропущена
Ссылки навигации ведут куда обещаютВсе пункты меню кабинета открываются на живом сервере с живой базойcheck:navпропущена
Страница API открываетсяДокументация отдаётся и её обвязка лежит на местеcheck:api-docsпропущена
Английская витрина остаётся английскойАбзац, набранный прямо в разметке, не виден ни одной проверке переводов — и английская страница молча становится наполовину русской; проверяются и наборы строк (есть ли английская ветка и нет ли в ней кириллицы), и сама разметка витриныcheck:englishгоняется вручную
Обещанный язык подкреплён словарёмПолноту словаря данных проверяет тип, но не его существование: язык, добавленный в locales.ts без словаря, молча отдаёт русский, а объявленный вычитанным — отдаёт его уже и без оговорки; заодно ловится строка, скопированная из русского, — она компилируется, выглядит переводом и глазами не опознаётсяcheck:languagesгоняется вручную
Страницы шаблонов реестра сходятся с контрактомДвадцать страниц отвечают тому, кто открыл файл реестра и не понимает, что писать, и вся их ценность в точности: имя колонки, приведённое приблизительно, бесполезно — по нему ищут строку в своём файле и не находят. «Дата отёла» вместо «Дата отела» пишется рукой сама, потому что в контракте «ё» стоит не вездеcheck:fgias-pagesгоняется вручную
Каждый адрес витрины открываетсяПроверки витрины читают код и ни одна не открывает страницу — так словарь и раздел исследований выложились с ошибкой сервера на каждом адресе статьи: сборка прошла, типы сошлись, указатели открывались, и поломка выглядела бедой отдельных страниц. Адреса берутся из карты сайта, чтобы новый раздел попадал под прогон сам, а не вносился в список рукамиcheck:siteнужен обход снаружи — место в ночном действии
Словарь не обещает лишнегоСсылка «читать дальше» на разбор или соседний термин выглядит рабочей всегда — подчёркнута и нажимается, — и о том, что её адреса нет, узнаёт только читатель, получив «страница не найдена»; заодно ловится статья короче двухсот пятидесяти слов, которой место строкой в указателе, и определение, не помещающееся в строку выдачиcheck:termsгоняется вручную
Разметка для поисковых систем не ссылается в пустотуРазметка собрана из того же, из чего нарисована страница, и сверять её с текстом незачем; ломается она снаружи — переименованный файл знака, ссылка на узел, которого никто не объявил, снятый с главной вызов, после которого повисают одиннадцать разборов сразу. Ни одно из этого на странице не видно: картинка из разметки нигде не показывается, а отказ получает только роботcheck:jsonldгоняется вручную
Метатеги постраничноСтраница без описания открывается, выглядит правильно и просто хуже находится — заметить это глазами нельзя ни на одной отдельной странице; заодно ловится заголовок, повторяющий хвост, который приклеит раскладка («… племенная книга — Племенная книга»: склеенную строку видно только в выдаче), и считается долг по переводу — русский текст, набранный прямо в разметке, ни одна проверка переводов не видитcheck:seoгоняется вручную
Числа в текстах против чисел в кодеВитрина и техническое описание называют количества — правил проверки, ограничений базы, коллекций обмена, — и это доказательство, ради которого страницу и читают. Устаревают такие числа молча: правило добавили, текст остался прежним. Держать их руками не удалось дважды: в описании стояло «пятьдесят три правила» при семидесяти семи в реестре и «тридцать проверок» в базе при сорока двух, и обе цифры врали месяцами ровно тому, кто пришёл за точностью. Ненайденное утверждение считается отказом наравне с разошедшимся числом: переписанная фраза делает прогон зелёным и бесполезнымcheck:numbersгоняется вручную
Разборы: страница, паспорт, источникиРазбор живёт в двух местах — строкой в списке и страницей; разъехавшись, они дают либо «страница не найдена» тому, кого мы позвали читать, либо страницу, куда никто не ведёт. Ссылка на первоисточник обязательна: без неё разбор превращается в пересказ, от которого весь раздел и отличаетсяcheck:notesгоняется вручную
Нарисованные экраны разделов доходят до страницыОпечатка в сравнении со слугом раздела не ошибка ни для языка, ни для типов: ветка просто не выполняется, и страница молча остаётся без рисунка; обратное тише — экран написан, вывезен наружу и нигде не вставленcheck:screensгоняется вручную
Исследования: части заполнены, требования не отстали от кодаУ разборов проверка была, у шести исследований — ни одной, а устроены они сложнее: семь частей, список требований к книге, свои источники. Требования успели отстать от кода и просили завести то, что уже заведено. Проверяются непустота частей, внешние ссылки с пояснением «что взято», существование внутренних адресов и то, что у требования есть место в кодеcheck:studiesгоняется вручную

Код и форматы

ПроверкаЧто сверяетКомандаСостояние
Серверные компоненты не передают функцийПропс-функция через границу «сервер → клиент» роняет сборку, и только её — в разработке страница работаетcheck:client-propsгоняется вручную
Переводы полны, а язык определяется как задуманоНи одной пустой строки и ни одного русского абзаца в нерусском языке; Accept-Language разбирается верно, а выбор человека сильнее догадкиcheck:i18nгоняется вручную
Хуки коллекций пишут внутри своей транзакцииНи одно обращение к Payload из хука не идёт мимо `req` — иначе не ошибка, а зависаниеcheck:hooksгоняется вручную
Раскладка, которую не видно на одной страницеМеню кабинета стоит выше заголовка на каждой странице; раскладка задаётся классами, а не свойством в style — свойство действует на любой ширине и старше класса, поэтому соседний grid-cols-1 или sm:flex-row рядом с ним молча перестаёт работать, и вёрстка ломается только на телефонеcheck:layoutПрод
Даты в четырёх часовых поясахПоказ дат не съезжает на сутки при смене пояса читателяcheck:timeПрод
Реестр проверок совпадает с тем, что можно запуститьПроверка без записи в реестре невидима на этой самой странице, а запись без команды обещает запуск, которого не будетcheck:registryгоняется вручную

Находки

Родословная без противоречийПрод

Качество книги

Находок: 8. Что именно не сошлось, видно вошедшим: разбор называет номера животных, а это уже данные книги, а не сведения о системе.

audit:pedigree

Чего этот раздел не говорит

  • Зелёное — это «сошлось», а не «работает правильно». Проверки сверяют то, что уже описано: числа с числами, схему с журналом, списки с отчётами. Ошибку, которой никто не придумал проверки, они не увидят.
  • Проверки данных смотрят одно хозяйство — самое большое из заведённых. Расхождение, которое возникает только у другого, здесь не найдётся.
  • Битые внешние ссылки не проверяются вовсе. Обход страниц знает только свои адреса; ссылка на чужой сайт, который закрылся, останется незамеченной.
  • Расхождение документации с кодом не ловит ничего. Описание API сверяется с ручками, а рассказ о процессах в «Документации» — ни с чем.