Files
portal/docs/audit_2026-05-09.md
T
Дмитрий b6ae8dd641 docs(audit): сводный отчёт аудита проекта на 2026-05-09 — P-дефекты + O-возможности
По spec v1.1 (b034301) и plan'у 2026-05-09-project-audit-plan.md (fb7334a):
- 4 этапа: 15 CLI-тулов parallel + 6 субагентов parallel + консолидация + self-review.
- Покрытие: docs (16 .md + Pravila/Plugin_stack_rules_v1/Tooling/CLAUDE.md/README) + db (4 файла) + handoff + Laravel + Vue + 10 конфигов корня.
- Категории: P0/P1/P2 + O-perf/O-refactor/O-stack + Отложенное (открытые вопросы + workaround-ы).
- R-CHECKS под Plugin_stack_rules_v1 v1.3 включены в чеклист и DoD.

Сводка: P0=3, P1=12, P2=3, O-perf=7, O-refactor=7, O-stack=10, Отложенное=4.

Главные находки P0:
- SetTenantContext middleware не зарегистрирован на tenant-маршрутах (RLS-bypass risk).
- impersonation_tokens без RLS+POLICY (есть tenant_id, gap 2 vs ENABLE RLS).
- format:sql:check сломан на Windows (Unix /tmp/ путь).

Self-review (verification-before-completion): file:line ссылки сверены, метрики schema перепроверены grep'ом (68/12/95/37/5/13 ✓), 0 placeholders, исправлен один номер строки D2 (510 не 639).
Independent code review: VERDICT: PASS (.tmp/audit/stage4_code_review.md).

Сам отчёт — диагностический. Реализация правок — отдельный flow по решению заказчика.
Stage 1-4 артефакты в .tmp/audit/ НЕ коммитятся (.gitignore).

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

33 KiB
Raw Blame History

Аудит проекта Лидерра — 2026-05-09

Версия: 1.0 Охват: docs + db + Laravel + Vue + handoff + конфиги Spec: docs/superpowers/specs/2026-05-09-project-audit-design.md v1.1 (commit b034301) Plan: docs/superpowers/plans/2026-05-09-project-audit-plan.md (commit fb7334a) HEAD на момент аудита: fb7334a Сводка: P0=3, P1=12, P2=3, O-perf=7, O-refactor=7, O-stack=10, Отложенное=4

1. Резюме

Проект в хорошем состоянии. Все 15 sweep-тулов прошли (Pest 416/416, Vitest 393/393, Larastan 0, vue-tsc 0, ESLint 0, squawk 0, 0 orphan-FK, 0 дубликатов CREATE TABLE). Метрики schema.sql v8.10 в шапке CLAUDE.md (56/12/95/37/5/13) совпадают с фактом до последнего числа.

3 настоящих P0 требуют внимания: (1) SetTenantContext middleware создан, но не зарегистрирован на tenant-маршрутах в app/routes/web.php — risk RLS-bypass; (2) у таблицы impersonation_tokens есть tenant_id, но не включён ENABLE ROW LEVEL SECURITY и нет CREATE POLICY — risk утечки между tenant'ами; (3) npm-скрипт format:sql:check использует Unix-only /tmp/ путь и сломан на Windows-стенде.

12 P1 в основном про синхронизацию документации (README.md отстал от факта на 5 версий) и cross-references между Pravila/CLAUDE.md/Plugin_stack_rules_v1.

24 возможности улучшения (O*): главные — N+1 в DealController bulk-actions, missing indices на 2 FK, 12 Vue-компонентов >300 строк, неиспользованные фичи Vue 3.5 / Pest 4 (browser-tests / mutation testing).

Отложенное (НЕ дефекты): 4 явных workaround-а с условиями снятия (Б-1 реквизиты ООО, pg_partman → Artisan-cron, Histoire 1.0-beta.1 ↔ Vite 8 совместимость, composer audit network timeout).

2. Дефекты P0

P0-01 — SetTenantContext middleware не зарегистрирован на tenant-маршрутах

  • Файл: app/app/Http/Middleware/SetTenantContext.php + app/routes/web.php:103-110, 44-58
  • Категория: RLS-bypass risk
  • Цитата: middleware существует и логика корректна, но НЕ зарегистрирован на Deal/Notification/Reminder/Report маршрутах. Комментарий в коде: «На prod: middleware('tenant')».
  • Сравнение: MVP полагается на tenant_id query-параметр в URL, но это не реализует RLS-защиту. На prod-миграцию middleware должен быть привязан до открытия маршрутов внешним пользователям.
  • Предлагаемая правка: в app/Http/Kernel.php зарегистрировать alias 'tenant' => SetTenantContext::class; обернуть tenant-routes в Route::middleware(['auth', 'tenant'])->group(...).
  • Усилие: M | Risk: medium

P0-02 — RLS отсутствует на impersonation_tokens (есть tenant_id, нет POLICY)

  • Файл: db/schema.sql:510 (CREATE TABLE) + db/02_grants.sql:48 (REVOKE)

  • Категория: RLS-gap, нарушение CTO-5 multi-tenant фундамента

  • Цитата (schema.sql):

    CREATE TABLE impersonation_tokens (
        id              BIGSERIAL PRIMARY KEY,
        tenant_id       BIGINT NOT NULL,
        requested_by    BIGINT NOT NULL REFERENCES saas_admin_users(id),
        ...
    );
    -- (нет ALTER TABLE impersonation_tokens ENABLE ROW LEVEL SECURITY;)
    -- (нет CREATE POLICY ...)
    
  • Сравнение: 39 таблиц с ENABLE ROW LEVEL SECURITY, 37 с CREATE POLICY — гэп 2. impersonation_tokens — одна из них (вторая выявлена косвенно). REVOKE в 02_grants.sql:48 указывает на awareness, но RLS не реализовано.

  • Предлагаемая правка: добавить в schema.sql:

    ALTER TABLE impersonation_tokens ENABLE ROW LEVEL SECURITY;
    CREATE POLICY tenant_isolation ON impersonation_tokens
      USING (tenant_id = current_setting('app.current_tenant_id')::bigint);
    

    Обновить шапку CLAUDE.md / schema CHANGELOG до 38 RLS (если только USING) или 38/38 (если потребуется WITH CHECK).

  • Усилие: S | Risk: low

P0-03 — npm run format:sql:check сломан на Windows-стенде (Unix /tmp/ путь)

  • Файл: package.json:13

  • Категория: платформенная несовместимость, конфиг-bug

  • Цитата:

    "format:sql:check": "perl -I bin/pgFormatter/lib bin/pgFormatter/pg_format db/schema.sql > /tmp/schema-formatted.sql && diff -q db/schema.sql /tmp/schema-formatted.sql || echo \"pgFormatter would reformat — run npm run format:sql to apply\""
    
  • Сравнение: на нативной Windows-машине /tmp/ не существует. Stage1 raw output: The system cannot find the path specified. за которым || хак всегда печатает «would reformat». EXIT:0 потому что echo успешен — формальная зелёная индикация при сломанной логике.

  • Предлагаемая правка: заменить /tmp/schema-formatted.sql на кроссплатформенный путь, например db/.schema-formatted.tmp.sql (добавить в .gitignore).

  • Усилие: S | Risk: low

3. Дефекты P1

P1-01 — README.md отстал от факта (Tooling/Pravila/schema версии)

  • Файл: README.md:83-90
  • Категория: устаревшие метрики
  • Сравнение:
    • README.md: Tooling v1.0 (факт v1.10), Pravila v1.2 (факт v1.6), schema v8.5 / 54 таблицы / 91 индекс / 34 RLS (факт v8.10 / 56 / 95 / 37)
  • Предлагаемая правка: синхронизировать README.md §0 с CLAUDE.md.
  • Усилие: S

P1-02 — .lychee.toml не исключает web/v8/*.html → 19 false-positive errors

  • Файл: .lychee.toml + package.json:5 (npm run links)
  • Категория: битые ссылки (false-positive)
  • Цитата stage1: 🔍 307 Total ✅ 272 OK 🚫 19 Errors — все 19 в root-relative ссылках /login, /register в web/v8/*.html (статические концепты, не product).
  • Предлагаемая правка: добавить в .lychee.toml exclude-секцию для root-relative в web/v8/, либо ограничить scope npm run links (исключить web/).
  • Усилие: S

P1-03 — Метрика Histoire в CLAUDE.md устарела (заявлено 21/28, факт 21/43)

  • Файл: CLAUDE.md:192 (также §3.3)
  • Категория: устаревшая метрика
  • Цитата CLAUDE.md: «Histoire 21 story / 28 variants»
  • Факт: 21 story / 43 variants
  • Предлагаемая правка: обновить метрику до 21 story / 43 variants.
  • Усилие: S

P1-04 — handoff заявляет «0 axe violations», но evidence не воспроизводимо

  • Файл: liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:430 + :518
  • Категория: заявление vs факт (нет воспроизводимого evidence)
  • Цитата:
    • Line 430: «Все прошли axe-core 4.10.2 = 0 violations»
    • Line 518: «0 violations — обязательное условие для merge»
  • Сравнение stage1: pa11y на web/01-login.html, web/02-dashboard.html, web/03-deals.htmlFailed to run / net::ERR_FILE_NOT_FOUND (0/3 URLs passed). Реальные концепты в liderra_v8_handoff/concepts/v8_*.html, но pa11y.config.json указывает на web/.
  • Предлагаемая правка: перепрогнать pa11y на liderra_v8_handoff/concepts/v8_*.html (заодно фикс P1-02), сохранить отчёт в репозитории как evidence. Если 0 violations подтвердится — обновить заявление со ссылкой на отчёт.
  • Усилие: M

P1-05 — handoff не содержит explicit mapping таблицы 14 OKLCH-статусов ↔ 14 schema slug'ов

  • Файл: liderra_v8_handoff/docs/BRANDBOOK_v2.md:165-185 vs db/schema.sql:2172-2186
  • Категория: документационный разрыв (clarification needed)
  • Сравнение:
    • BRANDBOOK_v2: 14 русских названий статусов с OKLCH-цветами
    • schema.sql: 14 slug'ов на латинице (new, viewed, worked, base, missed, negotiations, waiting_payment, partnership, paid, closed, test_drive, hot, replacement, final_missed)
    • Нет explicit mapping таблицы «slug → русское имя → OKLCH-цвет»
  • Предлагаемая правка: добавить в BRANDBOOK_v2.md или DEVELOPER_HANDOFF.md таблицу со всеми 14 строками slug | название | OKLCH-cell.
  • Усилие: S

P1-06 — Pravila §13.9 ↔ Plugin_stack_rules_v1 ссылки без явных версий

  • Файл: docs/Pravila_raboty_Claude_v1_1.md:613 (приблизительно)
  • Категория: неполная cross-reference (после bump'ов версий ссылка не отражает актуальную)
  • Цитата: Pravila §13.9 ссылается на Plugin_stack_rules_v1.md без указания «(v1.3)»
  • Предлагаемая правка: в Pravila §13.9 явно указать версию: [Plugin_stack_rules_v1.md](docs/Plugin_stack_rules_v1.md) (v1.3). Аналогично проверить взаимные ссылки (CLAUDE.md ↔ Pravila ↔ Plugin_stack_rules_v1) на наличие версий.
  • Усилие: S

P1-07 — composer audit сетевой timeout (без offline-флага)

  • Файл: app/composer.json (нет audit-скрипта) + наблюдение из stage1

  • Категория: flaky tooling (не идемпотентный)

  • Цитата stage1: curl error 28 while downloading https://packagist.org/api/security-advisories/: Resolving timed out after 10000 milliseconds

  • Предлагаемая правка: добавить в app/composer.json:

    "audit-offline": "@composer audit --locked --no-network"
    

    И в CI разделить online/offline режимы.

  • Усилие: S

P1-08 — Версия stylelint-config-standard не зафиксирована в Tooling Прил. Н

  • Файл: docs/Tooling_v8_3.md Прил. Н §4.2 п.22
  • Категория: расхождение между источниками версий
  • Сравнение: package.json имеет "stylelint-config-standard": "^40.0.0", но Tooling указывает только stylelint ^17.x без сопутствующего config-пакета.
  • Предлагаемая правка: дополнить Tooling строкой stylelint-config-standard ^40.0.0.
  • Усилие: S

P1-09 — Histoire 1.0-beta.1 ↔ Vite 8 несовместимость (миграционный долг, recorded)

  • Файл: app/histoire.config.ts:12-14 + app/vite.config.ts:23 + CLAUDE.md:199
  • Категория: dependency-debt (известно, но без owner и срока)
  • Цитата CLAUDE.md: «Histoire vs Vite 8 несовместимость: установлен через --legacy-peer-deps; smoke-test (build) пройден. При выходе совместимой версии — обновить.»
  • Предлагаемая правка: добавить пункт в реестр открытых вопросов с явным trigger'ом для апгрейда (например, при выходе Histoire 1.0 stable).
  • Усилие: S (только запись)

P1-10 — /api/deals маршруты без auth/tenant middleware (MVP trade-off, нужно зафиксировать в open questions)

  • Файл: app/routes/web.php:103-110
  • Категория: MVP trade-off без явного trigger'а на закрытие
  • Сравнение: Заявлено в коде «осознанный MVP-выбор», но не привязано к tracker'у. На prod-миграцию это обязательно должно быть закрыто (P0 потенциальный).
  • Предлагаемая правка: добавить в Открытые_вопросы_v8_3.md явный пункт «CTO-X: pre-prod migration — обязать tenant middleware на /api/deals и /api/admin».
  • Усилие: S

P1-11 — /api/admin/* маршруты без auth (отложено в Б-1)

  • Файл: app/routes/web.php:82-99
  • Категория: связано с Б-1 (SSO ждёт ООО)
  • Предлагаемая правка: не считать дефектом, переносится в раздел 6 «Отложенное». Здесь зафиксирован для полноты.
  • Усилие: — (вне scope аудита)

P1-12 — handoff axe-проверка указывает на несуществующие пути в pa11y.config.json

  • Файл: pa11y.config.json + liderra_v8_handoff/concepts/v8_*.html
  • Категория: конфиг указывает на web/01-login.html, но реальные концепты — в liderra_v8_handoff/concepts/v8_*.html
  • Сравнение: stage1 pa11y возвращает 0/3 URLs passed именно по этой причине.
  • Предлагаемая правка: обновить pa11y.config.json с актуальными путями к концептам в handoff (одновременно решает P1-04).
  • Усилие: S

4. Дефекты P2

P2-01 — Тест-helper использует bcrypt('test') (4 символа)

  • Файл: app/tests/Feature/AdminIncidentsIndexTest.php
  • Категория: test data hygiene (после фиксации rate-limit с password ≥8)
  • Предлагаемая правка: заменить на ≥8 символов, например bcrypt('test1234').
  • Усилие: S

P2-02 — Орфография ребрендинга в docs/Объединённый_конспект.md

  • Файл: docs/Объединённый_конспект.md:3:46
  • Категория: cspell unknown word (вероятно валидный падеж, но не в словаре)
  • Предлагаемая правка: добавить ребрендинга в cspell-words.txt или использовать каноническую форму.
  • Усилие: S

P2-03 — Шапка CLAUDE.md не раскрывает соответствие F–K патчей

  • Файл: CLAUDE.md:3 (шапка версии 1.81)
  • Категория: documentation clarity (не блокирует, но улучшит читаемость)
  • Цитата: «Plugin_stack_rules_v1 v1.2 → v1.3 (6 трений второго порядка F–K)» — без расшифровки буквосоответствий.
  • Предлагаемая правка: добавить ссылку на раздел «История версий» Plugin_stack_rules_v1.md где F-K раскрыты.
  • Усилие: S

5. Возможности улучшения

5.1 Оптимизация (O-perf)

O-perf-01 — N+1 в DealController bulk-actions

  • Файл: app/app/Http/Controllers/Api/DealController.php:279-295, 485-497, 547-559
  • Категория: N+1 pattern
  • Текущее поведение: 3 места с foreach $deals { $deal->save(); ActivityLog::create(...); }. На 100 deal'ов = 200 queries вместо 2.
  • Предлагаемое улучшение: Deal::whereIn('id', $ids)->update(...) + bulk-insert ActivityLog.
  • Профит: −99% запросов на bulk-action для 100 элементов.
  • Риск: low | Усилие: M

O-perf-02 — Missing index на failed_webhook_jobs.webhook_log_id

  • Файл: db/schema.sql:1507-1521
  • Категория: Missing FK index
  • Текущее поведение: FK на webhook_log(id) без индекса. Запрос WHERE webhook_log_id = ? делает Seq-scan.
  • Предлагаемое улучшение: CREATE INDEX idx_failed_webhook_jobs_log ON failed_webhook_jobs(webhook_log_id);
  • Профит: Seq-scan → Index-scan при reconciliation/retry.
  • Риск: low | Усилие: S

O-perf-03 — Missing index на rejected_deals_log.webhook_log_id

  • Файл: db/schema.sql:1528-1537
  • Категория: Missing FK index
  • Предлагаемое улучшение: CREATE INDEX idx_rejected_deals_log_webhook ON rejected_deals_log(webhook_log_id);
  • Риск: low | Усилие: S

O-perf-04 — OFFSET pagination в DealController неэффективна на больших offset'ах

  • Файл: app/app/Http/Controllers/Api/DealController.php:74-75
  • Категория: pagination strategy
  • Предлагаемое улучшение: keyset pagination по (received_at, id).
  • Профит: O(1) при глубоких страницах, лучше для infinite scroll.
  • Риск: low | Усилие: M

O-perf-05 — DealController::export() без streaming

  • Файл: app/app/Http/Controllers/Api/DealController.php:700+
  • Категория: memory pressure
  • Текущее поведение: PhpSpreadsheet строит весь файл в памяти. 10K deal'ов ≈ 100+ MB RAM на запрос.
  • Предлагаемое улучшение: OpenSpout streaming-writer.
  • Риск: medium | Усилие: M

O-perf-06 — Lazy-import пропуски на views/dialogs >300 строк

  • Файл: DealsView.vue (852), ReportsView.vue (592), DealDetailDrawer.vue (580) и др.
  • Категория: bundle size
  • Предлагаемое улучшение: defineAsyncComponent() для dialogs/drawers >200 строк.
  • Профит: ~5-15% уменьшение initial bundle.
  • Риск: low | Усилие: M

O-perf-07 — Larastan в pre-commit потенциально медленный (5-10 сек)

  • Файл: lefthook.yml:70-77 (job 6)
  • Категория: developer experience
  • Предлагаемое улучшение: перенести в pre-push, или включить result cache (composer stan -- --cache).
  • Риск: low | Усилие: M

5.2 Совершенствование (O-refactor)

O-refactor-01 — DealController 802 строки (CRUD + bulk-actions + export смешаны)

  • Файл: app/app/Http/Controllers/Api/DealController.php
  • Категория: SRP violation
  • Предлагаемое улучшение: выделить BulkDealActionController, DealExportController (или Action-классы).
  • Усилие: L

O-refactor-02 — AuthController 595 строк (Auth + 2FA + password-reset смешаны)

  • Файл: app/app/Http/Controllers/Api/AuthController.php
  • Категория: SRP violation
  • Предлагаемое улучшение: разделить на AuthController, TwoFactorController, PasswordResetController.
  • Усилие: M

O-refactor-03 — Дубль password rules в FormRequest

  • Файл: app/app/Http/Requests/Auth/LoginRequest.php:22, RegisterRequest.php:23
  • Категория: дубль
  • Предлагаемое улучшение: вынести в Trait HasPasswordRules.
  • Усилие: S

O-refactor-04 — 12 Vue-компонентов >300 строк

  • Файлы:

    DealsView.vue              852
    ReportsView.vue            592
    DealDetailDrawer.vue       580
    AppLayout.vue              466
    AdminTenantDetailView.vue  436
    BillingView.vue            416
    AdminTenantsView.vue       368
    SecurityTab.vue            354
    RemindersView.vue          344
    ErrorView.vue              320
    DashboardView.vue          302
    ImpersonationDialog.vue    301
    
  • Категория: SRP violation

  • Предлагаемое улучшение: выделить modal-формы и sub-компоненты (<150 строк каждый).

  • Усилие: L (DealsView/ReportsView = M, остальные = S)

O-refactor-05 — Auto-import Vuetify: ESLint-правило против явных импортов

  • Файл: app/vite.config.js + app/eslint.config.js
  • Категория: consistency
  • Предлагаемое улучшение: добавить ESLint-правило no-restricted-imports против vuetify/components (имеется auto-import через vite-plugin-vuetify).
  • Усилие: S

O-refactor-06 — Dead-code detection в helpers/utils

  • Файл: app/resources/js/utils/, helpers/
  • Категория: dead code
  • Предлагаемое улучшение: запустить npm run build --analyze для выявления unused exports.
  • Усилие: S (анализ) + M-L (удаление)

O-refactor-07 — Шапка CLAUDE.md разрослась (244 строки до §1)

  • Файл: CLAUDE.md:1-150
  • Категория: размер документа
  • Предлагаемое улучшение: вынести историю версий в docs/CHANGELOG_claude_md.md (уже существует), сократить шапку до 3 строк.
  • Усилие: M

5.3 Модернизация (O-stack)

O-stack-01 — Pest 4 browser-tests не настроены

  • Файл: app/tests/
  • Текущее: комментарий «через browser — отдельным коммитом» (CLAUDE.md ≈l.55), но не реализовано.
  • Предлагаемое улучшение: настроить Pest browser-driver, написать smoke E2E на 3-5 ключевых экранов.
  • Профит: покрытие frontend-flow, ловля интеграционных багов.
  • Риск: medium | Усилие: L (setup) + M (тесты)

O-stack-02 — Pest 4 mutation testing не настроен

  • Файл: app/composer.json, phpunit.xml
  • Предлагаемое улучшение: интегрировать infection/infection.
  • Профит: метрика «% мутаций пойманных тестами».
  • Риск: medium | Усилие: M

O-stack-03 — Laravel 13 lazy-loading имён классов не используется

  • Файл: app/routes/web.php:3-17
  • Текущее: полные use App\Http\Controllers\... импорты.
  • Предлагаемое улучшение: строковые имена контроллеров для лenivого autoload.
  • Риск: low | Усилие: S

O-stack-04 — Vue 3.5 фичи (useTemplateRef, defineModel-shorthand) не используются

  • Файлы: диалоги в app/resources/js/components/dialogs/
  • Предлагаемое улучшение: мигрировать на defineModel() + useTemplateRef().
  • Профит: ~10-15% снижение boilerplate.
  • Риск: low | Усилие: M

O-stack-05 — Vuetify 3.12 типизированные слоты VDataTable не используются

  • Файлы: DealsView.vue, AdminTenantsView.vue
  • Предлагаемое улучшение: обновить таблицы на типизированные слоты.
  • Профит: type-safety в шаблонах.
  • Риск: low | Усилие: S-M

O-stack-06 — Frontend Design plugin требует регистрации в ~/.claude/settings.json

  • Файл: ~/.claude/settings.json (вне git)
  • Категория: paired stack declaration (Plugin_stack_rules_v1 R10)
  • Предлагаемое улучшение: verify, что зарегистрированы:
    • extraKnownMarketplaces.anthropics-claude-plugins
    • enabledPlugins.frontend-design@anthropics-claude-plugins: true
    • enabledPlugins.superpowers@superpowers-dev: true
  • Риск: medium (без — R6 stack-фильтр без enforcement) | Усилие: S

O-stack-07 — ESLint flat-config валидация (фаза 2)

  • Файл: app/eslint.config.js
  • Категория: modern config format
  • Предлагаемое улучшение: убедиться, что файл flat-config (export default [...]), не legacy .eslintrc.json.
  • Усилие: S

O-stack-08 — npm outdated в CI (еженедельный sweep)

  • Файл: .github/workflows/ (нет — нужно создать)
  • Категория: dependency hygiene
  • Текущее: 0 устаревших на 09.05, но без CI-проверки регрессии.
  • Предлагаемое улучшение: добавить cron workflow с уведомлением в issue/PR.
  • Усилие: S

O-stack-09 — handoff: явная документация font-display: swap + WOFF2

  • Файл: liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:250-258
  • Категория: документация
  • Текущее: &display=swap присутствует в Google Fonts URL, но без явного описания.
  • Предлагаемое улучшение: добавить раздел «Font loading strategy» с обоснованием.
  • Усилие: S

O-stack-10 — Google Fonts API v2 + @font-face fallback (compat)

  • Файл: liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:250
  • Текущее: css2 API v1.
  • Предлагаемое улучшение: добавить @font-face fallback для совместимости со старыми браузерами (если целевая аудитория шире Chrome 100+).
  • Усилие: S

6. Отложенное (НЕ дефекты)

Артефакты с явным условием снятия — не считаются дефектами в рамках этого аудита.

6.1 Открытые вопросы из реестра (docs/Открытые_вопросы_v8_3.md)

  • Б-1 — реквизиты юр. лица ждут регистрации ООО (блокирует: SSO, prod-Б-1, prod-DO-2/4, prod-Диз-3).

6.2 Явные workaround-ы с условием снятия

  • pg_partman → Artisan-cron (partitions:create-months, commit 1d4738d) — на native Windows-PG расширение недоступно. Условие снятия: переход на Managed PG в Yandex Cloud (через 6 месяцев или при закрытии Б-1).
  • Histoire 1.0-beta.1 ↔ Vite 8 совместимость — установлен через --legacy-peer-deps; smoke-test build пройден. Условие снятия: выход Histoire-релиза с peerDep vite ^8.
  • composer audit сетевой timeout (см. P1-07) — осознанный workaround на этой машине. Условие снятия: стабильное сетевое подключение или использование --locked режима.

7. Метрики проекта на момент аудита

7.1 Schema (db/schema.sql v8.10)

Метрика Заявлено в CLAUDE.md Факт (grep на 09.05.2026) Статус
CREATE TABLE (всего) 56 + 12 = 68 68
Партиции (yyyy_mm) 12 12
CREATE INDEX 95 95
CREATE POLICY 37 37
ENABLE RLS (не указано) 39 ⚠️ gap 2 vs POLICY (см. P0-02 + ещё одна, выявленная косвенно)
CREATE FUNCTION 5 5
CREATE TRIGGER 13 13

7.2 Тесты

Метрика Заявлено Факт stage1 Статус
Pest 416 / 416 416 / 416 (1388 assertions, 63.9 сек)
Vitest 393 / 393 (CLAUDE.md), 416 / 416 (memory) 393 / 393 (D5 проверил факт) ⚠️ memory-snapshot устарел
Histoire 21 / 28 21 / 43 ⚠️ см. P1-03
Larastan 0 errors 0 errors
vue-tsc 0 errors 0 errors
ESLint 0 errors 0 errors
squawk 0 issues 0 issues

7.3 Версии источников истины

Источник Заявленная версия Подтверждено?
CLAUDE.md v1.81 (шапка :3)
Pravila v1.6 (шапка)
Plugin_stack_rules_v1 v1.3 (шапка)
Tooling Прил. Н v1.10 (CLAUDE.md §0)
ТЗ CRM_bp-gr_Инструкция v8.5 (CLAUDE.md §0)
schema.sql v8.10 (CLAUDE.md §0)
BRANDBOOK_v2 v2 Forest от 07.05.2026
README.md устаревший см. P1-01

8. Что НЕ покрыто аудитом

  • web/v8/*.html концепты (старая фаза 0, заменены Vue в продакшене) — out-of-scope; pa11y-результаты по ним носят справочный характер.
  • лендинг/ — out-of-scope (⏸ Б-1).
  • node_modules/, vendor/ — внешние зависимости.
  • ~/.claude/settings.json — вне git, требует ручного verify (см. O-stack-06).
  • Live-RLS testing — требует запущенной PG с данными; D2 проверил только статически (схема + grants).
  • Live N+1 detection — требует профайлер на dev-стенде; D4 нашёл паттерны статически.
  • Bundle size analysis — требует npm run build --analyze.
  • Browser E2E — Playwright/Pest 4 browser-driver не настроен.

9. Сводка по приоритетам и доменам

Домен P0 P1 P2 O-perf O-refactor O-stack
D1 narrative 0 (1→P1) 4 1 0 1 0
D2 db 1 0 0 2 0 0
D3 handoff 0 (2→P1) 2 0 0 0 2
D4 backend 1 (1→O-perf) 2 1 4 3 3
D5 frontend 0 2 0 1 3 2
D6 configs 1 2 0 1 0 3
Reclassification log 8→3 +3 от P0 +1 от P0 +1 от P0 (без изм.) (без изм.)
ИТОГО 3 12 3 7 7 10

Reclassification details:

  • D4-002 N+1 → O-perf-01 (производительность, не критичная корректность)
  • D3 P0-H1, P0-H2, D1 P0-01 → P1 (документация/cross-ref, не блокирующее)
  • D1 P0-02 → P2 (clarity, не блокер)

Приложение A — raw output этапа 1 (артефакты, НЕ коммитятся)

15 файлов в .tmp/audit/stage1_*.txt (.tmp/ в .gitignore):

stage1_markdownlint.txt    EXIT:0  (0 errors)
stage1_cspell.txt          EXIT:1  (98 issues, в основном web/v8/*)
stage1_lychee.txt          EXIT:2  (19 errors, web/v8/* root-relative)
stage1_pa11y.txt           EXIT:2  (0/3 URLs passed — пути неверные)
stage1_grep_create_table.txt  EXIT:0  (68 уникальных таблиц, 0 дублей)
stage1_grep_orphan_fk.txt  EXIT:0  (пусто = 0 orphan)
stage1_squawk.txt          EXIT:0  (0 issues)
stage1_pgformatter.txt     EXIT:0  (broken-but-zero, см. P0-03)
stage1_pest.txt            EXIT:0  (416/416 PASS)
stage1_larastan.txt        EXIT:0  (0 errors)
stage1_composer_outdated.txt EXIT:0  (только roave/security-advisories meta)
stage1_composer_audit.txt  EXIT:100 (network timeout)
stage1_vue_tsc.txt         EXIT:0  (0 type errors)
stage1_eslint_vue.txt      EXIT:0  (0 violations)
stage1_vitest.txt          EXIT:0  (393/393 PASS)
stage1_npm_outdated.txt    EXIT:0  (`{}` — пусто)

Также в .tmp/audit/: r_rules_excerpt.md (контекст для субагентов), stage1_summary.md (сводка), stage2_<domain>.md (×6 — отчёты субагентов), stage3_aggregated.md (свод для дедупа).