Commit Graph

6 Commits

Author SHA1 Message Date
Дмитрий 6383da7f12 chore(incident-followup): close 4 tails from 29.05 disk-full incident
ремонт: incident-followup cleanup batch — 4 хвоста

1. Larastan baseline regenerated (was 161 errors pre-existing IDE helper drift)
2. Deptrac Mail: [Model, Service] + ADR-005 amend (was 4 pre-existing violations)
3. PG logrotate config in setup-logrotate.yml
4. F1 6 mismatches — RCA updated (algorithm divergence trigger global vs verify per-tenant)

+3 cspell words: notifempty, missingok, верифицируется.

Ref: docs/incidents/2026-05-29-disk-full-pg-recovery.md §4-5
2026-05-29 14:45:28 +03:00
Дмитрий 6e5460be5e feat(slepok): Task 2.9 — SyncSupplierProjectsJob reads from snapshot (race 18:02→18:05 closure)
After Stage 2 запуска, 18:05 МСК sync читает project_routing_snapshots за tomorrow
МСК, не live projects.is_active. Это закрывает race 18:02 (snapshot) → 18:05 (sync):
клиент мог нажать «пауза» в эти 3 минуты, но мы всё равно докатываем зафиксированный
slepok поставщику (slepok-инвариант).

collectEligibleProjects() переписан с Project::on()->where('is_active', true)
на Project::on()->join('project_routing_snapshots AS snap', ...). Snapshot уже
отфильтрован по is_active/preflight_blocked/frozen_tenant; повторно проверяем
frozen-фильтр на случай freeze в эти 3 минуты. daily_limit_target /
delivery_days_mask / regions переопределяются значениями snapshot (slepok-семантика);
downstream syncGroup() работает без изменений.

Spec §4.2.4b. Closes race 18:02→18:05.

Plan: docs/superpowers/plans/2026-05-26-slepok-routing-protection.md §Task 2.9

Tests:
- tests/Feature/Jobs/Supplier/SyncSupplierProjectsJobSnapshotTest.php (4 new tests, PASS).
- tests/Feature/Supplier/SyncSupplierProjectsJobTest.php — 12 existing tests patched
  with insertSnapshotForTomorrow($project) helper (12/12 GREEN).
- tests/Feature/Supplier/SyncSupplierPreflightFilterTest.php — 2 existing tests
  patched (2/2 GREEN).
- tests/Pest.php — global helper insertSnapshotForTomorrow().

Combined sync regression: 19/20 PASS + 1 skipped (pre-existing).

Patched via 2 parallel Sonnet subagents per Pravila §15.1; controller-verified
combined regression.
2026-05-28 06:59:09 +03:00
Дмитрий e8db184e99 feat(slepok): Task 2.5 — LeadRouter reads from project_routing_snapshots (R-01 closure)
LeadRouter SQL переписан на JOIN с project_routing_snapshots по active_slepok_date:
до 21:00 МСК = today, после 21:00 МСК = today+1. is_active / delivery_days_mask /
daily_limit / regions / signal_type / signal_identifier берутся из snapshot.
Из live projects — только delivered_today (счётчик остатка лимита). Из tenants —
balance_rub (live auto-pause при нулевом балансе).

Active snapshot date вычисляется в PHP (метод activeSnapshotDate()) и
передаётся в SQL как параметр — тестируемо через Carbon::setTestNow,
исключает дрейф между PHP- и DB-часами.

Fail-loud: Log::error('lead_router.no_snapshot_for_active_date', ...) если
по активной дате слепка вообще нет ни одной строки snapshot'а (cron не отработал).

Closes R-01, R-04, R-06, R-07, R-08, R-15.
Partial: R-02 (через шеринг), R-09 (race), R-10 (editable identifier) — закрываются Task 2.6+.

Plan: docs/superpowers/plans/2026-05-26-slepok-routing-protection.md §Task 2.5
Spec: docs/superpowers/specs/2026-05-26-slepok-routing-protection-design.md §4.2.3

Tests added:
- tests/Feature/LeadRouter/SnapshotRoutingTest.php (4 tests, all GREEN locally)

Tests patched (downstream — добавлен createRoutingSnapshotFromProject() helper):
- tests/Pest.php — global helper createRoutingSnapshotFromProject()
- tests/Feature/LeadRouter/BalanceFilterTest.php (2/2 GREEN)
- tests/Feature/Services/LeadRouterTest.php (10/10 GREEN)
- tests/Feature/Jobs/RouteSupplierLeadJobTest.php (14/14 GREEN)
- tests/Feature/Supplier/DirectPlatformTest.php (6/6 GREEN)
- tests/Feature/Supplier/RouteSupplierLeadJobBillingTest.php (3/3 GREEN)
- tests/Feature/Supplier/SupplierConnectionTest.php (5/5 GREEN)
- tests/Feature/Integration/SupplierLeadFlowTest.php (2/2 GREEN)
- tests/Feature/Pd/DealCreatePdLogTest.php (2/2 GREEN)

Each test file isolated regression: GREEN. Combined run 49/50 with 1 flake on
quirk #77 (Faker unique domainName + cross-connection pgsql/pgsql_supplier
DatabaseTransactions scope mismatch) — pre-existing, NOT regression от Task 2.5.

Patched via 7 parallel Sonnet subagents per Pravila §15.1; controller-verified
isolated + combined regression (latter caught 1 subagent over-application:
paused project in SupplierLeadFlowTest получил snapshot, что нарушило логику
теста — fixed inline, по semantic match with SnapshotBackfillCommand SQL
WHERE p.is_active = true).
2026-05-28 05:48:15 +03:00
Дмитрий d6364dcde1 refactor(tests): consolidate linkProjectToSupplier helper to tests/Pest.php (Plan 2 review I-1/I-2) 2026-05-20 11:52:47 +03:00
Дмитрий 20d4682e21 feat(backend): Sprint 2 Phase A — Pest 4 browser scaffold + mutation + lazy-loading + Larastan cache
Sprint 2 Phase A (modernization). Закрытие audit O-stack-01/02/03 + O-perf-07:

- O-stack-01: Pest 4 browser-tests scaffold. testsuite Browser в phpunit.xml,
  Pest.php extend(...)->in('Browser'), tests/Browser/SmokeTest.php
  (login-flow + deal-create-flow). На Windows native PHP плагин
  pest-plugin-browser требует ext-sockets (отсутствует в стандартной
  сборке) и при автозагрузке вызывает socket_create_listen() ДО старта
  тестов, что ломает весь Pest. Поэтому плагин НЕ в require-dev,
  тесты помечены ->skip(...) с инструкцией активации на Linux CI.
  Скелет тестов в комментариях — на CI достаточно
  composer require pestphp/pest-plugin-browser --dev + npx playwright
  install + раскомментировать тела.
- O-stack-02: infection/infection ^0.32.7 в require-dev + app/infection.json
  (minMsi=50, source: Http/Models/Services). composer mutation script.
  Запуск отдельной задачей в CI (медленный). allow-plugins для
  infection/extension-installer.
- O-stack-03: Laravel 13 string-based lazy-loading в routes/web.php —
  убран блок use App\Http\Controllers\Api\* (16 импортов), все
  ссылки заменены на строки 'App\Http\...\X@method'. Контроллеры
  не загружаются автозагрузчиком при boot route'ов; класс резолвится
  только при матче маршрута. Использован строковый синтаксис, а не
  FQN-class — Pint default preset (fully_qualified_strict_types fixer)
  сворачивает FQN-class обратно в use, на строки не действует.
- O-perf-07: Larastan result cache через tmpDir: .phpstan-cache в
  phpstan.neon (cache-dir не дублируется флагом — phpstan не принимает
  оба источника). lefthook job 6 (larastan) использует этот же
  tmpDir автоматически. Ускорение инкрементальных pre-commit прогонов:
  на правке одного файла — переанализ только зависящих, не всего
  графа классов. .phpstan-cache в .gitignore.

Pest: 416/416 PASS + 2 skipped (browser smoke pending Linux CI).
Larastan: 0 errors above baseline.
Infection: vendor/bin/infection --version → 0.32.7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:18:38 +03:00
Дмитрий 30f0335f5f phase1(test): Pest 4 swap + reopen(CTO-12) — Pest 3 → Pest 4
Произошло так: при `composer require pestphp/pest pestphp/pest-plugin-laravel
--dev --with-all-dependencies` я не зафиксировал `^3` — composer подтянул
свежайшую Pest v4.7.0 + pest-plugin-laravel v4.1.0. Smoke-test
(`./vendor/bin/pest`) на default-тестах Laravel 11 прошёл 2/2 за 281 ms —
backward-compat с Pest 3 syntax подтверждён. Заказчик 08.05 (поздний вечер)
принял Pest 4 после live-проверки на стеке.

Бонус Pest 4: browser testing (без Dusk), stress testing, mutation
testing v2. Откат дёшев — `composer require pestphp/pest:^3`.

Что сделано:
- composer remove phpunit/phpunit (был direct dev-dep) — phpunit остался
  как транзитивная зависимость Pest
- composer require pestphp/pest:^4.7 pestphp/pest-plugin-laravel:^4.1 --dev
- Pest.php создан через `vendor/bin/pest --init` (`tests/Pest.php`)
- `vendor/bin/pest` smoke-test: 2 passed (Unit/Feature ExampleTest), 281 ms
- `vendor/bin/pest --init` упал на интерактивном промпте «Wanna show Pest
  some love?» в non-interactive PowerShell — Pest.php к этому моменту уже
  создан, нефатально

Reopen(CTO-12): по правилу «явная фиксация переоткрытий» обновлены
3 источника:
- docs/Открытые_вопросы_v8_3.md v1.15→v1.16: блок «Что изменилось в v1.16»,
  таблица §0 (CTO-12 переоткрыт+закрыт), запись §3 (Pest 4 + обоснование),
  финальный список §X (Pest 4)
- docs/Tooling_v8_3.md v1.2→v1.3: блок «Что нового в v1.3», §3.1 п.4
  (Pest 4 в boost:install), §3.4 строка 18 (Pest 4 + бонусы), §6 п.2
  (конфликт Pest↔PHPUnit), §10.1 п.9 (процедура установки + warning про
  --init на Windows non-interactive)
- CLAUDE.md v1.4→v1.5: §0 источники (Tooling v1.3, Реестр v1.16),
  §3.2 строка 18 (Pest 4), §7 п.5 (Pest 4 в boost:install), футер с
  историей версий

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:56:20 +03:00