Files
cloud-ip-validator/docs/changes/2026-10-03_17-21_verdict-no-late-results-summary.md
T
ayurishchevandClaude Sonnet 5.5 864208238f Show egress/ingress levels in the registry; freeze checks at the verdict
Registry: the "last result" column now also shows, per level (egress,
ingress), how many of the recorded checks of the latest cycle succeeded, split
by check family (tcp-22 and tcp-443 are both "tcp"). One grouped query per
chunk of addresses; new fields last_cycle_id, egress, ingress in
GET /admin/registry; the dashboard renders them under the verdict.

Verdict integrity (migration 0010):
- the prober is handed an address once per site and attempt, not on every
  poll, so results are no longer overwritten by later probe rounds;
- UpsertCheckIfOpen refuses writes once the address is aggregating or has its
  verdict, or for an older attempt; senders get {"ok":true,"ignored":N} and a
  result_dropped event is recorded;
- the checking window counts from checking_started_at, not from assigned_at;
- checks.recorded_at (server clock) and checks.after_verdict (flag for rows
  written after the verdict in existing data);
- the verdict rule is a pure function (computeVerdict) and the aggregated
  event carries the egress/ingress check counts.

Rebuilt bin/control-api and bin/admin-dashboard to match. Plans and summaries
are in docs/changes; README, API, USAGE, DASHBOARD and DIAGRAMS are updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 17:59:52 +03:00

5.6 KiB

Вердикт без опоздавших результатов — итог

План: 2026-10-03_17-21_verdict-no-late-results-plan.md.

Статус: код и тесты готовы. На стенд не выкладывалось, контрольный прогон не проводился.

Что сделано

  1. Один проход площадки на адрес. GET /probers/{site}/assignments больше не отдаёт адрес, для которого эта площадка отметила complete в текущей попытке (DB.ListCheckingForSite). Другим площадкам адрес выдаётся, новая попытка выдаёт его снова. Prober не менялся.
  2. После вердикта запись закрыта. DB.UpsertCheckIfOpen пишет проверку только если строка очереди существует, попытка совпадает с текущей и состояние не aggregating, done, failed, occupied. Проверка состояния и запись — один SQL-запрос. Отброшенный результат не создаёт и не меняет строк. Ответ 200 {"ok": true, "ignored": N}; на каждый адрес пишется событие result_dropped. UpsertCheck и Orchestrator.RecordCheck оставлены как обёртки для существующих вызовов.
  3. Окно проверки с её начала. Новая колонка ip_queue.checking_started_at (ставится в SetChecking, сбрасывается при повторе). isReadyToAggregate считает checking_window_seconds от неё, для старых строк — от assigned_at.
  4. Время записи по часам сервера. Колонка checks.recorded_at, обновляется при каждой принятой записи.
  5. Вердикт воспроизводим. Правило вынесено в чистую функцию computeVerdict; в событие aggregated добавлены egress и ingress (число проверок по уровням).
  6. Старые данные. Миграция 0010_verdict_integrity.sql: recorded_at = created_at, колонка after_verdict = 1 у строк, записанных после вердикта (julianday(checked_at) > julianday(aggregated_at)).

Проверка на копии боевой БД (запуск 02.10, 141 005 проверок)

Миграция применилась за секунды, user_version = 10, recorded_at заполнен у всех строк. Помечено after_verdict:

всего провалов успешных
ingress 1430 844 586
egress 351 32 319

В плане было 1426 и 350: они считались сравнением строк времени, миграция сравнивает точнее.

Тесты

  • internal/db/queries_verdict_integrity_test.go: запись принимается, пока адрес проверяется, и идемпотентна; после начала агрегации и после вердикта не создаёт и не меняет строк; результат прежней попытки отбрасывается; recorded_at растёт, created_at нет; ListCheckingForSite (готовая площадка, другая площадка, новая попытка); checking_started_at ставится и сбрасывается; миграция 0010 на базе версии 9.
  • internal/orchestrator/verdict_integrity_test.go: таблица computeVerdict (7 случаев); окно от начала проверки и запасной вариант assigned_at; полный цикл: после вердикта результат не принят, сохранённые проверки не изменились, вердикт равен пересчёту.
  • internal/httpapi/handlers_verdict_integrity_test.go: площадка получает адрес до complete, после него нет, другая площадка получает; результаты prober и агента после вердикта дают ignored, строки не изменены, два события result_dropped.
  • go build ./... && go vet ./... && go test ./... проходят.

Что не проверено

  • Работа на живом стенде и контрольный прогон. Гипотеза «часть прежних провалов ingress — проверка отвязанного Floating IP» подтвердится или нет только им: после изменения доля провалов ssh, tcp-22 и icmp должна упасть. Если не упадёт, причину нужно искать в другом месте.
  • Нагрузка на сеть площадок изменится: prober теперь зондирует адрес один раз, а не при каждом опросе.

Что дальше

Пересборка и перезапуск только control-api (prober и агенты без изменений), копия БД перед миграцией, контрольный прогон на небольшой партии (300 адресов). Раздел «Аналитика» строится после этого и получает миграцию 0011.