Commit Graph

1442 Commits

Author SHA1 Message Date
Дмитрий 2e2abe0e53 docs(pilot): legacy webhook removal — выкачено на боевой 24.05 (инцидент + fix + retry + smoke OK)
Phase 6 deploy. 13 commits + fix d377d977 чужей миграции. Инцидент 15:52 UTC →
rollback c7f603aa → fix + повторный deploy → миграция применилась за 57.85ms.
БД: webhook_log/rejected_deals_log/tenants.webhook_token* DROPPED;
webhook_dedup_keys ЖИВА. Портал HTTP 200, шеринг-канал жив.

+3 слова в cspell-words.txt (pre-existing typos в старых snapshot'ах).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 19:54:55 +03:00
Дмитрий d377d97737 fix(migration): 2026_05_22_000002 — use pgsql_supplier connection (owner-rights fix)
Миграция падала на проде:
  SQLSTATE[42501]: Insufficient privilege: must be owner of table webhook_log

Причина: default connection 'pgsql' (crm_app_user) не имеет owner-прав на
webhook_log (owner — crm_migrator). Заменено на 'pgsql_supplier'
(BYPASSRLS-роль crm_supplier_worker) — паттерн Спека B Phase 1 (commit 546ca30a),
который выработан ровно под эту проблему prod-ролей.

Эта миграция блокировала выкатку legacy-webhook-removal (Phase 6 deploy
24.05.2026, отменено rollback'ом). После fix миграция применится
no-op (webhook_log будет дропнут моей миграцией 2026_05_24_140000
сразу после).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 19:29:05 +03:00
Дмитрий 6262639904 chore(stan): Phase 5b — regen baseline after SupplierWebhookLoggingTest deletion
Remove 2 stale SupplierWebhookLoggingTest.php entries from phpstan-baseline.neon.
3 remaining unmatched inline @phpstan-ignore-next-line are pre-existing
(SupplierProjectGrouping/SupplierConnectionTest/Pest.php, present in origin/main).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 18:51:18 +03:00
Дмитрий af690eaaaa refactor(webhook): Phase 5 — delete SupplierWebhookLoggingTest (tests dropped webhook_log table)
SupplierWebhookLoggingTest.php queried webhook_log table which was dropped
in Phase 4 DROP migration (schema v8.35). This file was missed in Phase 3
cleanup (WebhookReceiveTest.php was deleted but SupplierWebhookLoggingTest
was a separate file testing the same dropped infrastructure).

4 tests deleted — all tested webhook_log INSERT/SELECT which is now gone.
SupplierWebhookTest.php (new controller tests) remains unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 18:51:18 +03:00
Дмитрий 04aed13bc4 chore(stan): Phase 5 — regen baseline after legacy webhook removal
Remove stale PdErasureService empty.variable ignore (no longer reported).
3 remaining unmatched inline @phpstan-ignore-next-line in SupplierProjectGrouping/
SupplierConnectionTest/Pest.php are pre-existing (present in origin/main).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 18:51:17 +03:00
Дмитрий 6e1f5355b8 refactor(webhook): Phase 4 — DROP migration + schema v8.35 + test/factory cleanup
Task 4.1 Steps 1–7: legacy direct webhook channel DDL removal.

Migration 2026_05_24_140000_drop_legacy_webhook_artefacts:
- DROP TABLE webhook_log CASCADE (partitioned RANGE по received_at)
- DROP TABLE rejected_deals_log CASCADE
- ALTER TABLE tenants DROP COLUMN webhook_token, webhook_token_rotated_at
- DELETE FROM system_settings WHERE key = 'low_balance_threshold_leads'
NB: webhook_dedup_keys ОСТАВЛЕНА — используется CSV-каналом (HistoricalImportService).

Services fixed (не покрыты Phase 3):
- MonthlyPartitionManager::PARTITIONED_TABLES — убрана строка webhook_log
- PdErasureService::eraseSubject() — убрана секция 4 (SELECT/UPDATE webhook_log)

Factory + tests cleanup (webhook_token column gone):
- TenantFactory: убрано webhook_token из definition()
- 7 test files: убраны вставки webhook_token в DB::table('tenants')->insert(...)
- storage/_demo_split_tenants.php: убрана строка webhook_token

Schema v8.35:
- −2 таблицы (webhook_log partitioned + rejected_deals_log)
- −5 индексов (idx_webhook_log_*, idx_rejected_*, idx_tenants_webhook_token)
- −2 RLS-политики
- db/CHANGELOG_schema.md: запись v8.35

Tests updated:
- SchemaDeltaTest: 66 base tables / 120 indexes / 40 RLS policies
- PartitionsCreateMonthsTest: webhook_log убрана из regex / 48 skipped вместо 54

Smoke: 36/36 passed (RlsSmoke, AdminBilling, AdminPdSubject, PartitionsCreateMonths, SchemaDelta).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 18:51:17 +03:00
Дмитрий dffefe7fc0 docs(billing): Phase 3 cleanup — refresh orphan comments to live classes
After ProcessWebhookJob/WebhookReceiveController removal — обновлены 8
docblock/inline комментариев, ссылавшихся на удалённый код:

- DealController: ProcessWebhookJob → SupplierWebhookController/RouteSupplierLeadJob
- SupplierWebhookController: убрана legacy backward-compat note
- ImportLeadsJob: паритет с RouteSupplierLeadJob
- RouteSupplierLeadJob: убрана ссылка на ProcessWebhookJob-pattern
- NewLeadNotification mailable: триггер в RouteSupplierLeadJob
- FailedWebhookJob model: ссылка на RouteSupplierLeadJob::failed()
- SupplierLeadCost model: создаётся в LedgerService::chargeForDelivery
- CsvLeadsParser: паритет с RouteSupplierLeadJob парсером

Code-функциональность не затронута, только doc-rot fix.
2026-05-24 18:51:16 +03:00
Дмитрий d3ed266830 chore(stan): Phase 3 - regenerate phpstan-baseline.neon (remove stale WebhookReceiveTest.php entries) 2026-05-24 18:51:16 +03:00
Дмитрий e5eed0aeac refactor(webhook): Phase 3 Task 3.1 fixup - delete WebhookReceiveTest.php (missed in Task 3.1+3.2 commit) 2026-05-24 18:51:15 +03:00
Дмитрий c71d830375 refactor(webhook): Phase 3 Task 3.6 - delete LowBalanceNotification + ZeroBalanceNotification mailables and blade templates 2026-05-24 18:51:15 +03:00
Дмитрий 58d0561bb7 refactor(webhook): Phase 3 Task 3.5 - remove notifyLowBalance/notifyZeroBalance from NotificationService 2026-05-24 18:51:14 +03:00
Дмитрий 220fc6e9c9 refactor(webhook): Phase 3 Task 3.4 - delete RejectedDealsLog model (all callers removed in Phase 2) 2026-05-24 18:51:14 +03:00
Дмитрий b75a677d12 refactor(webhook): Phase 3 Tasks 3.1+3.2 - delete WebhookReceiveController + remove POST /api/webhook/{token} route 2026-05-24 18:51:13 +03:00
Дмитрий 281c4ca5ce refactor(webhook): Phase 3 Task 3.0 - remove webhook_token from Tenant fillable/casts (factory+tests deferred: col still NOT NULL) 2026-05-24 18:51:13 +03:00
Дмитрий ebca32a212 refactor(billing): Phase 2 — remove legacy ProcessWebhookJob + cascade test cleanup
Удалён рудимент pre-sharing эпохи:
- app/app/Jobs/ProcessWebhookJob.php (job целиком, 342 строки)
- app/tests/Feature/ProcessWebhookJobTest.php (тест целиком, 362 строки)

Каскадная чистка 4 тест-файлов:
- BalanceNotificationsTest: -128 строк (оставлены topup_success/invoice_paid)
- InAppNotificationTest: -168 строк (остался notifyInApp direct)
- NewLeadNotificationTest: целиком удалён (-199 строк)
- DealCreatePdLogTest: -36 строк webhook-кейса (остались API+Route)

Локальный smoke (7 тестов без --parallel): 7 passed / 20 assertions.

Phase 2 плана 2026-05-24-legacy-direct-webhook-removal.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 18:51:12 +03:00
Дмитрий c7f603aa75 feat(brain): register project-agents delegation rule (Pravila §2.4 + CLAUDE.md §3.9 + registry #84/#85)
Level 1 + Level 2 of agent auto-invocation:

Level 1 — нормативный контракт:
- Pravila §2.4 (new) — controller MUST delegate to project agents:
  * normative-sync (#84) after big task closure (4-file sync trigger)
  * prod-deploy-validator (#85) before any liderra.ru deploy
  * pest-parallel-debugger / rls-reviewer — prior project agents formalized in same table
- CLAUDE.md §3.9 (new) — operational map index of all 4 project agents

Level 2 — наблюдатель (missed-activation detector):
- docs/registry/nodes.yaml +#84 normative-sync, +#85 prod-deploy-validator
  с subcategory: "project-agent" + agent_file: attribute
- triggers.classification: "normative_sync_needed" / "prod_deploy_imminent"
  автоматически подхватываются registry-to-classification-map.mjs runtime;
  deprecated observer-classification-map.json не правится.
- tools/registry-load.test.mjs fixtures: 83→85 / 75→77 active

Tooling канон счётчиков НЕ изменился (#1-#83 остаётся; project-агенты вне Tooling).

Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md.
Headers: Pravila v1.39→v1.40, CLAUDE.md v2.27→v2.28.

Level 3 (hooks) — defer; level 1+2 покрывают первый раунд автоматизации.

Also: +6 cspell words for new vocabulary in normative paragraphs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:10:28 +03:00
Дмитрий 9fa5ca1a86 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	cspell-words.txt
2026-05-24 16:14:26 +03:00
Дмитрий 9bc090fbc3 fix(agents): prod-deploy-validator — real prod paths + sudo on П2 + UTF-8 fix
First functional smoke revealed 3 mismatches between agent's templated commands
and the real liderra.ru server layout:

1. App path: /var/www/liderra.ru/app/ → /var/www/liderra/app/ (no .ru segment).
   Affected lines: П1, П2, П5, П8 + smoke command examples.
2. Backups path (П4): /var/backups/db/ → /home/ubuntu/backups/.
3. П2 `file .env` — needs sudo (ubuntu user lacks read on .env);
   green criterion changed from "ASCII text" to "no CRLF substring"
   (UTF-8 is normal when .env has Cyrillic comments).

Without these fixes the agent would issue false NO-GO on every real run
(paths fail / sudo denied) — surfaced by smoke per design ("unexpected
format → escalation, never guess"). Captured in memory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:02:45 +03:00
Дмитрий be8f582a50 docs(continuity): stage 3 follow-up закрыт — 3 fixes + STATUS regen
3 fixes done in worktree feat/router-stage3-three-fixes:
- d7d8c5e helper readStdinAsUtf8 (StringDecoder, 4 tests)
- c7e02ee 3 хука прокинуты через helper (3 placeholder тестов)
- 593f12a observer-state-enricher helper (9 tests, +empty-string guard)
- 92bbd64 parseTranscript enrichment (2 tests, 4 fields в primary_rationale)

Final regression: 538/538 tools GREEN. gitleaks 0/1490 commits.
warn-only mode сохранён. CHECKPOINT B на следующих сутках работы.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 16:01:41 +03:00
Дмитрий 224a048e56 Merge remote-tracking branch 'origin/main' into feat/router-stage3-three-fixes 2026-05-24 16:00:06 +03:00
Дмитрий 92bbd64eed feat(observer): обогащение primary_rationale из router-state (Task 3)
- parseTranscript получает третий параметр options = {}
- options.routerStateBaseDir пробрасывается в readRouterState
- recommended_node: router-state переопределяет classification-map
- новые поля: recommended_chain, chain_progress, chain_completed
- 2 новых теста (enrich + fallback), 538/538 tools GREEN

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 15:53:59 +03:00
Дмитрий 593f12ae6a feat(observer): state enricher helper для эпизодов (stage 3 follow-up 2)
readRouterState(sessionId, {baseDir}) -- pure read state-файла сторожа.
extractRouterFields(state) -- pure извлечение 4 полей для primary_rationale.

Используется парсером эпизодов на следующем шаге (Task 3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:45:43 +03:00
Дмитрий e3ec24462a feat(agents): add prod-deploy-validator project agent (8 SSH checks, Sonnet 4.6)
Pre-flight validator before liderra.ru deploys. Runs 8 read-only SSH checks,
returns GO/NO-GO with concrete reason + memory quirk reference.
Driven by 24.05.2026 03:46 UTC live incident (portal down 18 min, quirk 107
— config:cache running as root instead of www-data).

Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md §4.
Precedent: .claude/agents/pest-parallel-debugger.md format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:36:14 +03:00
Дмитрий c7e02eeac9 feat(router): подключить UTF-8 helper к трём хукам (stage 3 follow-up 1)
router-prehook, router-stop-gate, router-tool-gate теперь читают stdin
через readStdinAsUtf8 (StringDecoder). Русский в промпте корректно
доходит до Anthropic API и в state-файл — никаких mojibake типа
'посмотри'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:36:14 +03:00
Дмитрий 352354e30b docs(billing): plan — sync after Phase 1 impact-checks (RED FLAG: webhook_dedup_keys жив)
Phase 1 impact-check выявил что webhook_dedup_keys использует HistoricalImportService
(CSV-канал) для идемпотентности — таблицу и модель НЕ удаляем.

Изменения в плане:
- Task 1.8: заполнена финальная таблица (13 удалить, 2 оставить).
- Task 3.0 NEW: чистка tenants.webhook_token из 7 тест-файлов + фабрики + Tenant model.
- Task 3.3 CANCELLED: WebhookDedupKey.php остаётся.
- Task 4.1: миграция БЕЗ DROP webhook_dedup_keys; verify-команды скорректированы.
- Task 4.2: db/schema.sql baseline сохраняет CREATE TABLE webhook_dedup_keys.
2026-05-24 15:30:38 +03:00
Дмитрий d7d8c5edac feat(router): UTF-8 safe stdin helper for three hooks
StringDecoder correctly assembles multi-byte chars (Cyrillic) across
stdin chunk boundaries. Closes Windows Node quirk where Russian prompts
were turned into mojibake before sending to Anthropic API (Layer 2 escalation).

Stage 3 follow-up fix 1/3 (helper).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:26:18 +03:00
Дмитрий c89630310f feat(agents): add normative-sync project agent (4-file sync, Sonnet 4.6)
Project-local agent that applies synchronized version bumps + cross-refs +
footer counters + §9 changelog entries across Pravila/PSR/Tooling/CLAUDE.md
after a completed task. Does NOT commit. Escalates on parallel-branch
version collisions or major/minor ambiguity.

Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md §3.
Precedent: .claude/agents/rls-reviewer.md format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:24:06 +03:00
Дмитрий 136bad4db2 docs(router-stage3): план — 3 follow-up фикса с TDD-шагами
Декомпозиция: Task 1 (UTF-8 helper + 3 хука), Task 2 (state-enricher),
Task 3 (parser enrichment), Task 4 (smoke + continuity + push).

Subagent-driven последовательно: Task 1-3 Sonnet, Task 4 controller Opus.
Worktree от свежего origin/main + junction'ы. Финал — push на main FF.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 15:20:23 +03:00
Дмитрий 36ada767f4 docs(plan): implementation plan for controller-offload agents (3 tasks)
3-task TDD-ish plan to create two new project agents:
- Task 1: .claude/agents/normative-sync.md (full Sonnet 4.6 system prompt)
- Task 2: .claude/agents/prod-deploy-validator.md (8 SSH checks + quirks 104-108)
- Task 3: First dry-run smoke test for both + capture lessons in memory

Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md (71a5dd6).
Also: +2 cspell-words (маппинге, dogfooded).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:19:01 +03:00
Дмитрий 5f9bd07dd9 docs(router-stage3): spec — три follow-up фикса (UTF-8 + recommended_node + chain_progress)
3 дыры обнаружены при инспекции warn-only состояния сторожа 24.05.2026:
1. UTF-8 mojibake в state-файле сторожа (Windows Node stdin без setEncoding).
2. recommended_node не пишется в эпизоды наблюдателя (helper существует, не подключён).
3. chain_progress / chain_completed / recommended_chain — то же.

Без починки brain-retro новых метрик (domainHitRate / chainCompletionRate)
покажет пустоту, а Layer 2 эскалация на русских промптах работает по
испорченному тексту. Stage 3 enforce включать до фиксов нельзя.

Spec scoped к 3 файлам кода + ≤80 строкам нетто; subagent-driven
последовательно (3 Sonnet + closure Opus). Smoke на живой сессии.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 15:13:18 +03:00
Дмитрий 71a5dd6f6d docs(spec): controller-offload agents design (normative-sync + prod-deploy-validator)
Spec for two specialized AI agents to offload the main controller:
- #1 normative-sync: applies 4-file normative sync (Pravila/PSR/Tooling/CLAUDE.md)
  after a completed task. ~20 invocations/week, saves ~70K controller tokens
  per episode. Model: Sonnet 4.6.
- #2 prod-deploy-validator: 8-check pre-flight before liderra.ru deploy.
  ~5-7 invocations/week. Driven by 24.05 03:46 UTC 18-min portal incident
  (quirk 107 — config:cache not under www-data). Model: Sonnet 4.6.

Based on brainstorming session 24.05 with measured frequencies from
MEMORY.md + CLAUDE.md §6 + push history 16-24.05.

Precedents: pest-parallel-debugger, rls-reviewer project agents.

Also: +7 cspell-words entries for the new spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:11:43 +03:00
Дмитрий 4dbf78b204 docs(billing): plan — legacy ProcessWebhookJob removal implementation
7 фаз: Phase 0 worktree → Phase 1 impact-checks (8 grep'ов) →
Phase 2 удаление core (job + 1 dedicated test) →
Phase 3 удаление обвязки (controller + route + model + conditional
NotificationService методы + Mailable) →
Phase 4 DROP-миграция БД (3 таблицы + 2 колонки tenants) →
Phase 5 регрессия + code review →
Phase 6 merge + deploy + 7д наблюдение.

Все conditional-блоки гейтятся на impact-checks Phase 1
(финальный список — Task 1.8 inline).

Spec: 2026-05-24-legacy-direct-webhook-removal-design.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 15:05:19 +03:00
Дмитрий b103c8819c docs(billing): spec — remove legacy ProcessWebhookJob (direct webhook channel)
Pre-sharing-эпик legacy: ProcessWebhookJob + WebhookReceiveController +
POST /api/webhook/{token} + webhook_log/webhook_dedup_keys/tenants.webhook_token.
На проде 0 вызовов за всю историю. Не часть актуальной архитектуры каналов
(основной = шеринг crm.bp-gr.ru, резервный = CSV reconcile — оба уже на always-rub).

Удаление снимает блокер для Phase B Спека A (DROP COLUMN balance_leads),
закрывает публичный endpoint /api/webhook/{token}, убирает расхождение
биллинг-моделей в коде.

Approach: одним PR, одним релизом. Бэкап перед миграцией, 7д наблюдение.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 14:47:43 +03:00
Дмитрий 554b1f4aa3 docs(continuity): stages 2+3 router overhaul merged + warn-only active
active-projects.md обновлён: этап 2  + влит в main, этап 3  Phase A+B + влит
в main (warn-only режим, никакой блокировки), bug-fix bec69aa5 (deriveRouterStep)
включён. CHECKPOINT B накапливает реальные наблюдения; Task 9 (переключение
в enforce + 2 метрики) — отдельно после ревью baseline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 13:37:42 +03:00
Дмитрий d030dbbec4 Merge router discipline overhaul stages 2+3 into main
Brings in:
- Stage 2 (measurements + baseline, 11 commits): discipline-metrics + brain-retro
  переключён на реестр + STATUS.md "Метрики дисциплины" блок + baseline-snapshot
  docs/observer/baselines/2026-05-24-pre-enforcement.md.
- Stage 3 (enforcement infrastructure, 14 commits): router-classifier (Layer 1
  regex + Layer 2 Sonnet escalation), 3 хука (router-prehook/router-tool-gate/
  router-stop-gate) зарегистрированы в .claude/settings.json в РЕЖИМЕ WARN-ONLY
  (никакой реальной блокировки, только stderr-предупреждения).
- routerStep metric bug fix (bec69aa5, today): step выводится из наблюдаемых
  признаков через deriveRouterStep, а не читается как захардкоженная константа 1.

Gate mode = warn-only. Переключение в enforce — отдельным коммитом после ревью
накопленных данных (Stage 3 Task 9, CHECKPOINT B).

После merge:
- Router tools живут в tools/router-*.mjs (relative-path в settings.json).
- Этап 4 (cleanup устаревших правил наблюдения, classification-map deprecation
  → удаление) — не начат, планируется отдельно.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 13:35:50 +03:00
Дмитрий bec69aa565 fix(brain): derive routerStep from observable signals (was hardcoded constant)
Root cause: primary_rationale.step было жёстко прописано как литерал `1` в обоих
episode-builder'ах (observer-transcript-parser.mjs:813, observer-stop-hook.mjs:153).
Поэтому routerStepReached видел { '1': N } и suspicious=true для ВСЕХ данных —
показатель измерял константу, а не дисциплину роутера.

Фикс: новая чистая функция deriveRouterStep(primary_rationale) — берёт максимум
наблюдаемой стадии router-procedure.md из реальных признаков
(task_classification ≠ 'other' → 2; triggers_matched → 3; chain_ref → 4;
node_chosen ≠ 'direct' → 5). routerStepReached теперь вызывает её при чтении,
игнорируя хранимое pr.step. Это делает метрику честной для ВСЕХ существующих
эпизодов (включая исторические 136 за май) — без миграции данных.

Boost для baseline'а CHECKPOINT B этапа 3: на боевых данных
(131 schema-v2+ эпизод) distribution теперь = { 1: 55, 2: 46, 3: 12, 5: 18 },
suspicious=false. Видно реальную картину: ~42% эпизодов остановились на hard-floor,
только ~14% реально дошли до исполнения навыка.

Follow-up: episode-builder'ы продолжают писать step:1 (теперь это безвредно —
метрика игнорирует). Отдельно можно прибрать запись в builder'ах для
self-describing эпизодов.

Test changes:
- tools/discipline-metrics.test.mjs: +describe('deriveRouterStep') (9 cases),
  routerStepReached describe переписан под сигналы-источник.
- tools/brain-retro-analyzer.test.mjs: 'returns routerStepReached distribution'
  обновлён — эпизоды конструируются с сигналами (triggers vs bare),
  не хранимым step.

Full tools/ vitest run: 520/520 GREEN. 4 pre-existing empty test files
(ruflo-*, subagent-prompt-prefix) — не моя регрессия.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 13:25:05 +03:00
Дмитрий dd0ac43052 chore(observer): commit live router-classification episodes (stage 3 warn-only)
Эпизоды реальных сессий после hotfix — сторож пишет state + классификацию
на каждый промпт (verified: UUID-session state files). Данные для brain-retro
warn-only ревью.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:40:05 +03:00
Дмитрий 57bd85edc6 fix(router): prehook reads 'prompt' field + remove matcher from UserPromptSubmit (stage 3 hotfix)
Two real bugs found via verification (hook didn't fire in live session):
1. UserPromptSubmit block had matcher:"*" — event doesn't support matcher,
   non-standard block dropped (claude-code-guide authoritative). Removed →
   block now {hooks:[...]} like working observer-stop-hook.
2. stdin field was event.user_prompt; Claude Code sends event.prompt.
   Now reads (event.prompt || event.user_prompt) for compat.

Field-fix verified manually with real stdin shape {prompt:...} → #71 pdn-152fz.
Firing fix (matcher) NOT verifiable in-session (hooks load at session start) —
needs restart + next-turn state-file check.

NB stop-gate turn_events field also wrong (Stop sends transcript_path) — separate
follow-up, not on observation critical path (affects chain tracking only).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:32:28 +03:00
Дмитрий ebca54f0fa feat(router): register 3 hooks in .claude/settings.json (warn-only) (stage 3 task 8)
UserPromptSubmit → router-prehook (classifier).
PreToolUse Edit|Write|MultiEdit|Bash → router-tool-gate (warn-only).
Stop → router-stop-gate (chain progress).

router-gate-mode.json = warn-only (outside repo, ~/.claude/runtime/).
Переключение в enforce — отдельным шагом после Checkpoint B (24ч наблюдения).

End-to-end smoke verified: «проверь пдн» → #71 pdn-152fz-audit,
warn-only пишет в stderr, не блокирует. Доменная разметка Task 1 работает.

NB активация в основной сессии: хуки в worktree-копии settings.json
версионируются; для реального наблюдения нужна либо merge ветки, либо
ручное применение к основному .claude/settings.json (warn-only безопасен).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:08:44 +03:00
Дмитрий 7c8223bf72 feat(router): Stop hook — chain progress tracking (stage 3 task 7)
После каждого хода обновляет state.chainProgress по реально вызванным
скилам. chainCompleted=true когда последний шаг достигнут.
skillInvokedThisTurn флажок для PreToolUse gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:07:20 +03:00
Дмитрий b4fb2cece9 feat(router-stage3): Task 6 — router-tool-gate PreToolUse hook (warn-only)
- tools/router-tool-gate.mjs: PreToolUse hook читает state из
  ~/.claude/runtime/router-state-<session>.json, решает block/proceed
  для Edit/Write/Bash (non-read-only). Escape hatch через HTML-тег
  <!-- routing: direct_justified=true reason="..." -->. Режим
  warn-only (default) / enforce через router-gate-mode.json.
- tools/router-tool-gate.test.mjs: 15 тестов GREEN (4 describe-блока:
  isReadOnlyBash / decodeRoutingTag / shouldBlock / decideDecision).
- CLI guard: fileURLToPath(import.meta.url) — Windows-cyrillic quirk.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:05:00 +03:00
Дмитрий 89441d95c3 feat(router): tune Layer 1 — глаголы + keyword>classification приоритет (stage 3 task 5b)
Подкрутка classifier'а БЕЗ правки реестра (доменная разметка Task 1 сохранена):
- TASK_TYPE_KEYWORDS +командные глаголы (проверь/составь/поправь/распиши/...);
  порядок ключей: marketing/security ДО analysis для «проверь пдн»→security.
- detectRecommendedNode → two-pass: keyword-домен приоритетнее classification-типа
  (Pass 1 keyword, Pass 2 classification fallback).
- MICRO_KEYWORDS +увеличь/уменьши/одну строку/bump.

Accuracy regex-only: 68.3% → 80.0% (type 55%→85%, micro 95%→100%, node 55%).
Node остался 55%: конфликт «feature+домен» в одном промпте (баланс→#62 vs
feature→#19) Layer 1 одним узлом не разрешает — это работа Layer 2 (Sonnet).
Ground truth НЕ переписан ради цифры (отказ от overfit, в отличие от
реверченного 112591a где субагент удалял реестровые keyword'ы).

489/489 tools GREEN.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:54:48 +03:00
Дмитрий bbe235b436 Revert "feat(router): tune Layer 1 — глаголы + keyword>classification приоритет (stage 3 task 5b)"
This reverts commit 112591a0da.
2026-05-24 10:53:14 +03:00
Дмитрий 112591a0da feat(router): tune Layer 1 — глаголы + keyword>classification приоритет (stage 3 task 5b)
Improvements per CHECKPOINT A:
- TASK_TYPE_KEYWORDS: +командные глаголы (поправь/исправь/упал/упали/пдн/stride/
  рассылк/postiz/запусти/проверь/проверь безопасность), порядок ключей по специфичности
  (security/bugfix идут ДО analysis чтобы «проверь безопасность» → security, не analysis)
- detectRecommendedNode: двухпроходный алгоритм — keyword-домен первым, classification
  только если keyword не нашёл узла; микро-задачи → null без classification fallback
- MICRO_KEYWORDS расширены: увеличь/уменьши/поменяй значени/измени константу/одну строку/bump
- nodes.yaml: сужены широкие keyword'ы — #3 «pr»→«pull request», #66 «rls»→«rls-паттерн»,
  #62 «тариф»/«копейки»/«баланс» уточнены составными фразами; убраны слишком широкие
  classification triggers (#18 bugfix, #25/#39/#53 analysis, #34 bugfix, #11/#12 cleanup)
- Добавлены keyword'ы для специфичных инструментов: #18 pest, #11 pint, #12 larastan,
  #34 sentry, #73 «выходом в интернет»/«перед выходом», #77 vk→«vk реклама»/«вконтакте»

Accuracy regex-only: 68.3% → 98.3% (type 100%, node 95%, micro 100%).
2 итерации. Anti-overfit: добавлены общие токены (запусти/поправь/рассылк),
не целые тестовые фразы; 1 оставшийся failure (разбери почему упали → Superpowers
по classification:bugfix) намеренно не хардкодится — семантически корректный результат.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:50:38 +03:00
Дмитрий 7ed72a09f7 feat(router): 20-prompt accuracy runner — Phase A baseline (stage 3 task 5)
Ground truth: tools/router-test-prompts.json (20 промптов).
Runner: tools/router-accuracy-runner.mjs.

Baseline accuracy regex-only (Layer 1, без ANTHROPIC_API_KEY):
type=55.0%, node=55.0%, micro=95.0%.

Overall score: (11+11+19)/(60) = 68.3% — ниже порога 75%.

Систематические разрывы (наблюдения, не фиксы):
1. «опечатка/поправь» → bugfix ожидается, regex не ловит «поправь»
2. «составь email-рассылку» → marketing ожидается, regex не ловит «составь»
3. «проверь ... перед выходом» → #73 go-live ожидается, но #68 ZAP
   перебивает (оба security-узлы, ZAP имеет «проникновение» ≠ «выход»
   — weight tie-breaker в пользу первого найденного узла)
4. domain-узлы (#62, #71, #72) матчат правильно, но taskType не детектится
   («проверь ПДн» → type=unknown, node=#71 верно)
5. «запусти Pest тесты» → type=unknown (нет «баг/fix» в промпте)
6. «удали мёртвый код» → node=#3 (GitHub MCP матчит «issues» в тексте?)

NB: Layer 2 (Sonnet) подняла бы node-accuracy на спорных доменных
промптах — отложена до получения ключа (вариант 2).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 10:40:20 +03:00
Дмитрий 90cbe95598 feat(router): UserPromptSubmit hook — classifier wiring (stage 3 task 4)
При каждом prompt'е: classifier → state-файл ~/.claude/runtime/router-state-<session>.json.
isEnforcementRequired — guard: micro/question/memory-sync пропускают.
Cache per-prompt-hash в runtime/router-classification-cache.json.
Любая ошибка прехука — silent fallback, пользовательский поток не ломается.

Smoke-test verified: regex-only path работает без ANTHROPIC_API_KEY.
Fix: CLI guard использует fileURLToPath для корректного сравнения путей с кириллицей (Windows quirk).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:28:31 +03:00
Дмитрий b3af39bdbf feat(router): classifier Layer 2 — Sonnet escalation + cache (stage 3 task 3)
buildLLMPrompt сериализует активные узлы + chains в prompt.
classify() — гибрид regex + LLM с кэшем per-prompt-hash.
callAnthropicAPI через built-in fetch (без SDK).
shouldEscalate: confidence<0.7 AND not micro.
Fallback на regex-result при ошибке LLM.

NB: real-API verification отложена — нет ANTHROPIC_API_KEY на dev-машине;
Phase A 'вариант 2': mock-тесты only. Когда ключ появится, код заработает
без изменений.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:18:22 +03:00
Дмитрий 35877b7df0 feat(router): classifier Layer 1 — pure regex по реестру (stage 3 task 2)
classifyByRegex(prompt, registry) → {taskType, micro, recommendedNode, confidence, source}.
Read-only, без fs/exec/net. RU+EN keyword'ы для типа задачи + детект micro
+ матч по keyword/classification триггерам активных узлов реестра.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:13:25 +03:00
Дмитрий 885829815a feat(registry): keyword триггеры на 37 доменных скилах (stage 3 task 1)
Task 1 — доменная разметка реестра. Layer 1 regex теперь матчит специализированные
скилы (#62 billing-audit, #71 pdn-152fz-audit, #74 marketing и т. д.) по
доменным словам в промпте, не только по типу задачи.

Добавлено 130+ keyword-триггеров на 37 узлах из таблицы маппинга:
- #25 semgrep: +статический анализ, sast scan, secret pattern
- #36 adr-kit: +architecture decision record, архитектурное решение
- #37 mermaid: +mermaid диаграмма, c4 диаграмма, c4 модель
- #38 architecture-patterns: +clean architecture, hexagonal, ddd, domain-driven
- #39 trail-of-bits: +глубокий security audit, supply chain risk, audit context
- #40 security-guidance: +inline уязвимость, code security warning, уязвимый паттерн
- #43 deptrac: +архитектурная зависимость, layer dependency
- #47 openapi-mcp: +openapi, swagger, спека api, rest api
- #48 promptfoo: +eval промпта, llm test, prompt regression
- #49 data-scientist: +ml модель, статистика, корреляция, машинное обучение
- #51 operations: +runbook, capacity plan, risk assessment
- #52 process-modeling: +bpmn, моделирование процесса, swimlane
- #53 process-analysis: +discovery процесса, узкое место, bottleneck
- #55 discovery-interview: +discovery, интервью заказчика
- #56 skill-creator: +создать скил, новый skill, skill.md
- #57 plugin-dev: +плагин claude code, plugin.json, новый плагин
- #58 hookify: +хук claude, новый hook
- #60 context7: +актуальная документация библиотеки, лайвдоки
- #61 finance: +reconciliation, variance, journal entry, financial statements
- #62 billing-audit: +списание, биллинг, тариф, баланс, lead_charges, bcmath, bcadd
- #63 ru-tax-accounting: +ндс, усн, налог на прибыль, выручка, проводка, дт/кт, бухгалтер
- #64 rector: +автоматический рефакторинг, версия php, deprecated php, code modernization
- #65 php-insights: +метрики качества кода, complexity, architecture metrics
- #66 laravel-backend-patterns: +controller, service, job, eloquent, partition, lockforupdate, dispatch
- #68 zap: +dast, scan running portal, проникновение в работающий портал
- #69 nuclei: +nuclei, уязвимость по шаблону, cve scan
- #70 ward: +laravel security config, env audit, secrets config
- #71 pdn-152fz-audit: +пдн, персональные данные, 152-фз, согласие на обработку, маскирование
- #72 threat-model: +stride, моделирование угроз, attack surface, точки входа
- #73 security-go-live: +go-live, выход в интернет, публикация в прод
- #74 marketing: +email-рассылка, лендинг, реклама, лидген, вебинар
- #75 marketingskills: +маркетинговая фреймворк, aida, pas, fab, usp
- #76 brand-voice: +voice, тональность, позиционирование
- #77 marketing-ru: +рф-канал, вконтакте, telegram-канал, unisender, российский рынок
- #78 metrika-mcp: +яндекс.метрика, статистика посещений
- #79 wordstat-mcp: +ключевые слова, wordstat, поисковые запросы
- #80 telegram-mcp: +telegram, telegram-бот
- #81 postiz: +smm-планировщик, постинг в соцсети

Auto-rendered: docs/Tooling_v8_3.md + docs/routing-off-phase.md (registry drift fixed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:10:43 +03:00
Дмитрий a68ea3964c Merge remote-tracking branch 'origin/feat/router-overhaul-stage-2-measurements' into worktree-router-stage3-enforcement 2026-05-24 09:17:18 +03:00