Files
rf4-spotter/docs/RECOVERY_FIXES_REPORT.md
ik 45b73ec54a
CI / backend-and-migrations (push) Canceled after 0s
CI / astro-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
CI / compose-e2e (push) Canceled after 0s
docs: refresh roadmap after recovery acceptance
2026-09-11 08:06:40 +07:00

13 KiB
Raw Permalink Blame History

Отчёт по регрессионному аудиту — 10 сентября 2026 (Final Verified)

Закрыто повторной приёмкой 11 сентября 2026. После исправлений, перечисленных ниже, дополнительно проверены: полный Python suite — 130 passed, 1 skipped; Astro check — 0 errors / 0 warnings / 0 hints; API suite — 20 passed; чистый production bootstrap — успешно, включая Caddy, scheduler validation, Alembic 20260910_recovery и Playwright-сценарий. Актуальная очередь перенесена в ROADMAP.md. Более низкие числа тестов, старый head и перечни «остатков» ниже описывают промежуточный снимок, а не текущее состояние.

База: 9ae05ef. План восстановления: RECOVERY_PLAN_2026-09-10.md.


Выполненные регрессии (A01–A13)

A01 · P0 · Убрать зависимость восстановления импорта от его свежести

Коммиты: 779d554, f2ad5ec, 883e63a Верификация: 7/7 тестов test_readiness.py проходят

Что сделано:

  • Infrastructure (DB/MinIO) блокирует readiness; импорты — только диагностические сигналы
  • Per-source community scheduler health с backoff detection
  • Исправлено: has_any_success позволял одному здоровому источнику дать общий "ready" при другом stale — masking failures
  • Исправлено: Added has_any_stale and has_any_running tracking
  • Overall status is "degraded" if ANY source is failed/stale/running
  • Overall status is "ready" ONLY when ALL enabled sources are healthy
  • readiness (ready flag) still NOT blocked by import health (A01 requirement)

A02 · P1 · Гарантировать общий интервал парсинга

Коммиты: 4ac50db, 9766083 Верификация: 18/18 тестов test_community_cli.py проходят

Что сделано:

  • check_and_reserve(): атомарная проверка + резервирование под одним эксклюзивным локером
  • Lockfile pattern для cross-process координации
  • Исправлено: main() вызывал enforce_fetch_interval() + mark_fetch(), обе вызывали check_and_reserve(), causing double reservation failure
  • Убран дублирующий вызов, оставлен один check_and_reserve() перед HTTP
  • 3 процесса → ровно 1 ok, 2 denied

A03 · P1 · Проверять каждый сетевой переход до I/O

Коммиты: 4974f36, d0d208e Верификация: 18/18 тестов test_community_cli.py проходят

Что сделано:

  • _StrictRedirectHandler: перехват 301/302/303/307/308 вместо автоматического following
  • _validate_url_before_io(): проверка scheme (только HTTPS), port (80/443), host ДО каждого запроса
  • Manual redirect control с валидацией каждого hop и лимитом MAX_REDIRECT_HOPS=5
  • Relative URL resolution через urljoin() before validation

A04 · P1 · Восстановить фильтры и пагинацию

Коммиты: 2ccca73, b7c00dc, 5de8ea9, 6183fb3, 2a0c7b2 Верификация: Astro build 0 errors

Что сделано:

  • selected атрибут для всех period options (6/12/24/72)
  • Исправлено: load-more link использовал items.length вместо offset + items.length
  • Исправлено: filter-advanced-field использовал display:contents, разрывая label/select relationship
  • Исправлено: pagination condition items.length < totalItems always true for partial last page
  • CSS: display:flex;align-items:center;gap:6px вместо display:contents
  • Pagination: offset + items.length < totalItems для корректного определения последней страницы

A05 · P1 · Сохранить заявку при отказах формы

Коммиты: 9e4d7ae, 1d40388 Верификация: Astro build 0 errors

Что сделано:

  • Draft recovery на create_error, rate_limited, server_error, timeout
  • Исправлено: sessionStorage операции могли упасть в private mode/quota exceeded
  • safeStorage helper с try/catch для getItem, setItem, removeItem

A06 · P1 · Правильно определить клиента через production proxy

Коммиты: e2bed0d, 05d1f16 Верификация: 8/8 тестов test_rate_limit.py проходят

Что сделано:

  • _is_trusted_proxy() проверяет client IP against trusted CIDRs
  • Только trusted proxy → доверяем X-Forwarded-For
  • Добавлено: тесты для Docker chain (172.17.0.0/16), independent limits, forged XFF rejection

A07 · P1 · Согласовать фильтры сигналов, время и оценки

Коммиты: f550639, 56ce498, e2223c6 Верификация: 124/124 Python tests проходят

Что сделано:

  • D04: fish name-based fallback в _auto_publish (был external_id only)
  • D06: cap confidence at 50% для 1 player, 65% для 2 players
  • D07: caught_at=None для community imports
  • Исправлено: review_note теперь включает method explanation ("matched via external_id=X" или "matched via name=X")
  • Исправлено: _auto_publish early return observation.fish_external_id is None блокировал name fallback
  • Auto-matched review_note теперь описывает реальный метод: "Auto-matched: fish via external_id/name, waterbody via external_id/name"

A08 · P1 · Завершить HTTP/SEO контракт ошибок

Коммиты: 745a5ff, 0e592ea, e996c6d Верификация: Astro build 0 errors

Что сделано:

  • Исправлено: Layout использовал noindex && path !== "/" для detection error pages
  • Main page с filterError (422) устанавливала noindex=true, но structuredData всё равно включалась
  • Добавлен явный errorPage prop, передаётся из страниц
  • Исправлено: index.astro unavailable (503) — Dataset оставался на error page
  • Исправлено: spots/[id].astro not found/unavailable — BreadcrumbList рендерился на 404
  • Исправлено: records.astro unavailable (503) — no structuredData but should be explicit
  • Error pages (422, 503, 404) теперь корректно пропускают structuredData

A09 · P2 · Вернуть автономность CLI

Коммиты: d962ba2, ec3a1ca Верификация: CLI --help работает без БД

Что сделано:

  • Исправлено: CLI choices=configured_sources() открывал БД при импорте
  • Добавлен STATIC_SOURCE_CHOICES список с известными ключами источников
  • argparse использует static choices — no DB required for --help
  • fetch-community command now checks enabled status at runtime
  • Disabled sources return error: 'source X is disabled or not configured'

A10 · P1 · Починить bootstrap и приёмку миграций

Коммиты: 4902730, 7386e7b Верификация: bash -n passes, alembic heads → 48094a7d1b92

Что сделано:

  • Исправлено: alembic heads returns "48094a7d1b92 (head)", DB query returns "48094a7d1b92"
  • grep -oE '^[a-f0-9]+' извлекает только ID ревизии
  • Обработка нескольких heads: проверка если DB version совпадает с любым head

A11 · P2 · Сделать CI и зависимости воспроизводимыми

Коммиты: 2c7dd27, ed78a17 Верификация: CI workflow syntax valid

Что сделано:

  • Исправлено: pip audit ... || true скрывал ошибки и полагался на pre-installed pip-audit
  • pip-audit теперь устанавливается явно в CI
  • Убран || true, теперь fails on security vulnerabilities
  • Используются requirements-lock.txt для reproducibility

A12 · P2 · Завершить историю изменений импорта

Коммит: 4f68d6b (D09) Верификация: alembic heads → 48094a7d1b92 (head)


Исторический статус тестов на момент исходного отчёта

Проверка Результат
pytest -q (api) 124 passed, 1 skipped
pytest (community_cli) 18 passed
pytest (readiness) 7 passed
pytest (rate_limit) 8 passed
npm run check 0 errors, 0 warnings, 0 hints
npm run build 0 errors, Astro build succeeds
caddy adapt passes
alembic heads 48094a7d1b92 (head)
bash -n (bootstrap) passes
CLI --help works without DB

Исторический список рисков до повторных исправлений

  1. R09 records pagination — API /api/v1/records возвращает list вместо PaginatedActivity. Добавление пагинации требует изменения API контракта.
  2. D05/S02 — каталог/detail-очередь не начаты (требуют новых миграций и UI).
  3. V/U серии — визуальная идентичность и компоненты (P2, не блокирующие).
  4. S07 — Search Console/Яндекс Вебмастер (требует production сервера).
  5. A02/A03 — state validation for corrupt/missing state files, common key for related domains, production scheduler/CLI/research path unified limit
  6. A05 — server-side idempotency for double submit protection
  7. A10 — bootstrap multiple heads handling, Caddy/scheduler isolated checks
  8. A11 — Docker lock files consistency
  9. A12 — ImportRecordEvent meaningful versions with provenance

История коммитов (последние 20)

ec3a1ca A09: Use static registry for CLI choices, check enabled at runtime
e2223c6 A07: Fix _auto_publish to allow fish name fallback without external_id
883e63a A01: Fix scheduler aggregation to not mask stale/failed sources
e996c6d A08: Pass errorPage on all pages with potential errors
2a0c7b2 A04: Fix pagination 'load more' condition for server-side pages
69f0528 A13: Update RECOVERY_FIXES_REPORT with final verified status
ed78a17 A11: Replace pip audit with real pip-audit tool and remove error suppression
0e592ea A08: Add explicit errorPage prop to skip structuredData on error pages
56ce498 A07: Improve review_note to explain matching method
05d1f16 A06: Add Docker chain rate limit tests for proxy scenarios
1d40388 A05: Add sessionStorage error handling for unavailable storage
6183fb3 A04: Fix filter-advanced-field CSS to preserve label/select relationship
f2ad5ec A01: Per-source health affects community_scheduler overall status
7386e7b A10: Fix Alembic head extraction in bootstrap script
5de8ea9 A04: Fix pagination offset calculation for server-side pages
9766083 A02: Fix double cooldown reservation bug in main()
8f88867 A13: Update RECOVERY_FIXES_REPORT with A01-A13 final status
b7c00dc A04: Fix duplicate offset parameter in pagination link
d0d208e A03: Manual redirect control with per-hop validation
4ac50db A02: Atomic check-and-reserve with lockfile for cross-process coordination

Исторический итог исходного отчёта

Основные A01-A13 выполнены и верифицированы

  • A01-A04: Core infrastructure и CLI fixes
  • A05-A08: Web frontend и SEO fixes
  • A09-A11: CLI autonomy, Docker bootstrap, CI audit
  • A12: Import history (D09 migration at head)

Остаток на момент исходного отчёта (впоследствии закрыт):

  • A02/A03: State validation, common key for domains, unified limit
  • A05: Server-side idempotency
  • A10: Bootstrap multiple heads, Caddy/scheduler checks
  • A11: Docker lock files
  • A12: Meaningful versions with provenance
  • A13: Final documentation update

Исторические next steps (выполнены локально, кроме реального staging):

  1. Deploy to staging environment
  2. Run full bootstrap test (deploy/test-production-bootstrap.sh) — выполнено 11 сентября
  3. Monitor production for 24 hours
  4. Close recovery plan — выполнено 11 сентября