Commit Graph

64 Commits

Author SHA1 Message Date
Дмитрий e6752b5e4c feat(deploy): temporary SAAS_ADMIN_TEST_BYPASS flag for test server (off by default)
Allows SaaS-admin area in non-local/testing envs only when SAAS_ADMIN_TEST_BYPASS=true.
Default false -> production unaffected. Remove after Yandex 360 SSO (Б-1 + DO-4).
TDD: tests/Feature/Middleware/EnsureSaasAdminTest.php (2 passing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:00:16 +03:00
Дмитрий 3b6992d8e9 Merge remote-tracking branch 'origin/main' into feat/project-migration-redesign
# Conflicts:
#	docs/observer/STATUS.md
#	docs/observer/episodes-2026-05.jsonl
2026-05-21 06:20:38 +03:00
Дмитрий 233f9984fc chore(observer): backfill chain_ref on live May episodes (working branch) 2026-05-21 06:19:51 +03:00
Дмитрий 54b1de78b8 chore(observer): retrofill chain_ref on existing committed May episodes 2026-05-21 06:06:29 +03:00
Дмитрий df2d091174 feat(status-md): surface C6 chain-map sync row 2026-05-21 06:06:28 +03:00
Дмитрий d86d375ce4 docs(observer): chain attribution L1-L13 spec + plan + brain-retro #2
Brain-retro #2 (весь май) → кандидат: атрибуция canonical chains L1-L13.
Spec + 9-task TDD plan (chain_ref в primary_rationale, C6 sync-контролёр,
ретрофилл). Исполнение разблокировано — epic observer-instrument-expansion
влит в main. +cspell словарь.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 06:06:24 +03:00
Дмитрий 4f5cf263f6 docs(observer): chain attribution L1-L13 spec + plan + brain-retro #2
Brain-retro #2 (весь май) → кандидат: атрибуция canonical chains L1-L13.
Spec + 9-task TDD plan (chain_ref в primary_rationale, C6 sync-контролёр,
ретрофилл). Исполнение разблокировано — epic observer-instrument-expansion
влит в main. +cspell словарь.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 04:42:41 +03:00
Дмитрий 31b53557ac style(backend): pint concat_space fix in rector.php
lefthook pint (root:app/ + repo-relative {staged_files}) не обработал rector.php
при 058b239 — known pint-paths quirk. Ручной composer pint исправил concat_space.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:27 +03:00
Дмитрий be27713f6e feat(map): +4 A1 backend-tooling nodes + L14 chain (137->141 nodes, 155->165 edges)
NODES +rector/php_insights/backend_patterns/nightowl (все A1); EDGES +10 (реестр-связи
+ L14 backend-quality chain Rector->PHP Insights->Larastan + reuse Boost/billing-audit/Sentry).
Версии-метки v1.35/v2.22/v3.19/v2.19 + router-procedure v1.2. Browser-smoke: 141 узла /
165 рёбер, A1=7 узлов, 0 JS-ошибок (favicon 404 безвреден).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:27 +03:00
Дмитрий 60dd3e70b1 docs(normative): A1 backend-tooling #64-67 — Tooling v2.19 / PSR v3.19 / Pravila v1.35 / CLAUDE v2.22
Атомарный version-bump-набор (cross-ref-checker C2 STRICT). 16-я off-phase подкатегория
backend-tooling (раздел A1): #64 Rector + #65 PHP Insights (Composer dev-deps) + #66
laravel-backend-patterns (self-authored) + #67 NightOwl (DEFERRED). Счётчик 63→67 (87 total).
Tooling §4.39-4.42 (9-attribute blocks) + §0; PSR R10.1 Блок 1 note + R15.6; Pravila §13.2
абзац; CLAUDE §3.3/§6/§9/§0. ADR-013. cross-ref-checker + l1-watcher: 0 drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:26 +03:00
Дмитрий 54967147d7 docs(router): +4 backend nodes routing + L14 chain (routing-off-phase v1.3, router-procedure v1.2)
routing-off-phase v1.3: +4 строки routing #64-#67 (NightOwl DEFERRED) + связка L14
backend-quality chain (Rector->PHP Insights->Larastan->deptrac); scope §4.11-§4.42; #31-#67.
router-procedure v1.2: changelog +backend-tooling узлы в реестр step 3. ADR-013.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:26 +03:00
Дмитрий 1a02b4b5f2 docs(adr): ADR-013 backend-tooling boundaries (BT1-BT9) + NightOwl deferred spike
ADR-013: 4 узла A1 (#64-67) + границы BT1-BT9 + постуры. NightOwl DEFERRED
(native-Windows нет pcntl/posix + OSS без MCP + hosted 152-ФЗ) -> Linux/Б-1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:26 +03:00
Дмитрий 76ea9bbb04 feat(backend): Rector (#64) + PHP Insights (#65) install + configs
Rector: rector/rector ^2.4 + driftingly/rector-laravel ^2.3; app/rector.php
  (deadCode+codeQuality, conservative). composer rector / rector:fix scripts.
  dry-run baseline=16 files -> manual/CI posture, NOT blocking lefthook (ADR-013).
PHP Insights: nunomaduro/phpinsights; app/config/insights.php — SyntaxCheck removed
  (Windows subprocess crash + redundant), style not gated (Pint owns, BT4),
  security-check off. Baseline Code80/Complexity81/Arch75; floors set; composer insights -> 0.
allow-plugins += dealerdirect/phpcodesniffer-composer-installer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:26 +03:00
Дмитрий 62b5306548 feat(backend): laravel-backend-patterns skill (#66) — SKILL + conventions + evals
5 конвенций Лидерры (слоистость / RLS-aware / bcmath-деньги / идемпотентность / partition-aware)
с реальными file:line образцами. Границы: generic→architecture-patterns #38, аудит денег→billing-audit #62.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:21:26 +03:00
Дмитрий a0e18a1dd8 fix(supplier): matching по content в saveProjectMultiFlag — реальный портал возвращает name=B1_X
Реальный портал отдаёт rt-projects-load с name='B1_<id>' / 'B2_<id>' / 'B3_<id>'
и чистым идентификатором в поле 'content'. Старое matching по name === uniqueKey
никогда не совпадало с реальным ответом → idMap пустой → SyncSupplierProjectJob
молча выходил, ничего не записав в БД, а на портале оставались orphan-группы.

Объясняет ранее задокументированное в ЭТАЛОН «проект 5 вылечен вручную —
усыновлены 3 портальные записи». Заказчик обходил тот же баг руками.

Фикс — matching по content с fallback на name, чтобы мок-тесты с упрощённым
форматом (без content) продолжали работать; реалистичная фикстура добавлена
в SupplierPortalClientMultiFlagTest.

Verified:
- Pest supplier suite (SyncSupplierProjectJob/SyncSupplierProjectsJob/multi-flag): 16/16 passed
- E2E live на crm.bp-gr.ru: ProjectService::create + sync → supplier_projects записаны
  с ext_id, pivot заполнен, портал имеет 3 группы B1/B2/B3
- Multi-tenant ночной батч с computeOrder проверен на 79991177889 (T1+T2+T3+T4
  на одном identifier — формула max(max, ceil(Σ/3)) сходится с фактом)
2026-05-20 18:42:20 +03:00
Дмитрий 36c71ecb1e fix(supplier): одна группа на идентификатор — сливаем все регионы проекта
Портал crm.bp-gr.ru возвращает status=Doubles при попытке создать
вторую группу с тем же unique_key. Старый код делал одну B1/B2/B3-группу
на каждый регион проекта — вторая группа молча пропадала.

Теперь оба джоба (SyncSupplierProjectJob + SyncSupplierProjectsJob)
формируют ровно одну группу на идентификатор со всеми регионами:
- regions=[82,83] → tag='РФ', regions=[82,83] в одной группе
- regions=[] → tag='РФ', regions=[] (вся РФ)
- regions=[82] → tag='Москва', regions=[82]
subject_code=null во всех supplier_projects и project_supplier_links.

ProjectService::update() теперь триггерит SyncSupplierProjectJob
при изменении поля regions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 16:46:27 +03:00
Дмитрий c99362a3e5 chore(demo): скрипт разбивки 5 демо-учёток на 5 изолированных тенантов
Каждый логин (admin/manager1-4) → своя компания/тенант.
Идемпотентный: firstOrCreate + reassign tenant_id.
Запуск: php artisan tinker storage/_demo_split_tenants.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 16:08:08 +03:00
Дмитрий e35fc6c938 feat(projects): require region + explicit «Вся РФ» with warning gate
План 4 Task 4 эпика project-migration-redesign.

- NewProjectDialog: отдельный чекбокс «Вся РФ» (89 субъектов в autocomplete
  без sentinel сохранены) + inline v-alert предупреждение + подтверждение.
- Взаимоисключение: выбор субъектов снимает «Вся РФ» и наоборот.
- Гейт submit: блок если ни субъектов, ни подтверждённой «Вся РФ»
  (errors.regions = «Выберите регион...»); «Вся РФ» -> regions=[] на API.
- Лейбл autocomplete «Регионы» (убрано «(пусто = вся РФ)»).
- watch immediate:true — инициализация vsyaRf/edit-prefill при mount
  (чинит EditProjectDialog submit при модальном открытии).
- Vitest 3/3 новых + 22 passed соседних (NewProject/Edit/ProjectsView) без регрессий.
2026-05-20 14:34:27 +03:00
Дмитрий f1a3e9f02f feat(admin): supplier projects cleanup screen (list + bulk delete)
План 4 Task 3 эпика project-migration-redesign.

- AdminSupplierProjectsView.vue — v-data-table (источник/платформа/регион/
  лимит/кто заказывал/последняя поставка) + bulk-delete с v-dialog
  подтверждением + snackbar (deleted/failures).
- Роут /admin/supplier-projects (layout admin, requiresAuth, devIndex 31).
- AdminLayout nav-пункт «Проекты у поставщика».
- Vitest 3/3 (mount GET, bulk-delete confirm POST {ids}, disabled when empty).

NB: type-check имеет 3 pre-existing ошибки в DealDetailHero.spec.ts
(коммит 1412d3f, не Plan 4); файлы T3 type-check-чисты.
2026-05-20 14:34:25 +03:00
Дмитрий d0eecbbf79 feat(admin): supplier projects list (orderers, last delivery) + bulk delete
План 4 Task 2 эпика project-migration-redesign.

- AdminSupplierIntegrationController +projectsIndex (список supplier_projects
  + кто заказывал через pivot project_supplier_links -> projects -> tenants
  organization_name + дата последней поставки = max supplier_leads.received_at
  + subject_name из RussianRegions::CODE_TO_NAME, «РФ» при NULL subject_code).
- +projectsDestroy (bulk-delete: deleteProject на портале, затем локально;
  pivot снимается CASCADE; сбой строки не прерывает batch -> failures[]).
- Routes: GET /projects, POST /projects/delete в admin-группе.
- Pest 5/5 (26 assertions). phpstan-baseline +9 ignore (Pest TestCall).
2026-05-20 14:34:23 +03:00
Дмитрий b0ce510155 docs(observer): retro note + epic plan v1.1 (Task 21)
Closes the «Observer instrument expansion v2» epic. The retro note is
the source of all #1-#19 references in commit messages; the plan is
the procedural source (with REVISION v1.1 after parallel-session rebase).

Both kept in repo for traceability of the 20-commit epic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:47:45 +03:00
Дмитрий d1ddd28250 docs(plan): Plan 4 (админка + ЛК) — переделка миграции проектов
5 TDD-задач: тумблер режима экспорта (endpoint + UI), экран «Проекты у поставщика»
(кто заказывал/дата последней поставки + bulk-delete бэк/фронт), ЛК require-region
UI-гейт + «Вся РФ» предупреждение/подтверждение, полная регрессия. Финальный из
4 планов эпика. +cspell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:09:26 +03:00
Дмитрий 34458df474 docs(plan): Plan 3 (экспорт + заказ) — переделка миграции проектов
8 TDD-задач: R-SAVE live smoke (гейт), SupplierExportMode тумблер, формула заказа
max(наиб,ceil(Σ/3)) + убран split, saveProjectMultiFlag R5/R6/R7 (захват 3 id),
SyncSupplierProjectsJob группировка источник×субъект + pivot, онлайн mode-aware
sync + grouping-хелперы, крон 18:00, регрессия. Третий из 4 планов. +cspell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:09:24 +03:00
Дмитрий 467f1cdbf2 docs(plan): Plan 2 (входящее распределение) — переделка миграции проектов
5 TDD-задач: RegionTagResolver (тег субъекта -> код, зеркало regions.ts),
LeadRouter на pivot без phone-фильтра, LeadDistributor cap=3 (seedable RNG),
RouteSupplierLeadJob (cap + deal.subject_code из тега), регрессия.
Второй из 4 планов эпика. +cspell. Реализация не начата.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:09:22 +03:00
Дмитрий cd2353b57d docs(plan): Plan 1 (фундамент данных) — переделка миграции проектов
7 TDD-задач: supplier_projects.subject_code + per-subject unique (NULLS NOT
DISTINCT), pivot project_supplier_links (замена 3 FK-слотов), deals.subject_code,
seed supplier_export_mode, belongsToMany связи, backfill pivot, регрессия.
Первый из 4 планов эпика (см. spec §3). +cspell сид/бэкофилл. Реализация не начата.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 10:09:20 +03:00
Дмитрий 0fad4305d4 feat(brain): Forest polish + observer README entry for the dashboard 2026-05-19 16:23:52 +03:00
Дмитрий 2f60910b09 feat(brain): conflict three-layer panel (design / friction / correlation) +3 tests 2026-05-19 16:23:51 +03:00
Дмитрий f48d5115ce feat(brain): Агрегат view — metric tiles + node heat overlay 2026-05-19 16:23:51 +03:00
Дмитрий 774763c21c feat(brain): aggregator — node heat, distributions, redirect rate (+4 tests) 2026-05-19 16:23:50 +03:00
Дмитрий c1b690edd3 feat(brain): Лента auto-poll with pause (5s interval, view-driven) 2026-05-19 16:23:50 +03:00
Дмитрий e34b11aca5 feat(brain): Лента view — groupBySession + grouped feed UI 2026-05-19 16:23:49 +03:00
Дмитрий b4f4f441b5 feat(brain): Разбор view UI — list + filters + trajectory highlight 2026-05-19 16:23:49 +03:00
Дмитрий 475e233c2a feat(brain): filterEpisodes + 3 tests (Task 7 logic; UI deferred)
Worktree has no app/node_modules — vitest not run here; final regression
deferred to main-checkout post parallel-session release. Logic is a 7-line
pure filter; tests cover empty filter, classification, errors-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:23:48 +03:00
Дмитрий 3e289479f0 feat(brain): Карта view — plain topology + design conflicts list 2026-05-19 16:23:48 +03:00
Дмитрий 0cee520f0d feat(brain): dashboard shell + graph banner + view switching 2026-05-19 16:23:47 +03:00
Дмитрий c3392bef13 feat(brain): node attribution — episode signals to graph nodes 2026-05-19 16:23:46 +03:00
Дмитрий 7fed5bc18b feat(brain): episode JSONL parser + v1/v2 normalizer 2026-05-19 16:23:46 +03:00
Дмитрий 43028228c8 refactor(brain): extract automation-graph topology to a shared data file 2026-05-19 16:23:45 +03:00
Дмитрий f1092772fb feat(brain): static server + /api/episodes for the dashboard 2026-05-19 16:23:45 +03:00
Дмитрий 702c2ff7b5 fix(brain): correct vitest command in plan — run from app/
The config's include `../tools/*.test.mjs` resolves relative to its
own dir (app/), not cwd. Baseline verified 2026-05-19 from app/:
11 files, 169 tests passing, 0 failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:23:44 +03:00
Дмитрий b75f9e3d21 docs(brain): brain dashboard implementation plan
13 tasks across 3 phases — static server + topology extraction + 4 views
(Карта / Разбор / Лента / Агрегат). TDD on dashboard-core.js, smoke on UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:23:44 +03:00
Дмитрий 9e1a07aad3 chore(observer): remove 5 empty unknown-* episode stubs + commit session episodes
unknown-<ts>, empty events, fake outcome:success) — zero information.
Removed; remaining episodes carry real data. One-time cleanup of
pre-extension garbage — append-only stays the operational rule.
STATUS.md regenerated by C4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:40:37 +03:00
Дмитрий b2b9a75731 feat(observer): AskUserQuestion in-turn choice + parallel_session narrowing
#1 — detectAskUserQuestionChoice: when a turn contains an AskUserQuestion
whose answer exactly matches an offered option label, classify as
user_chose_from_options. The answered entry carries a structured
toolUseResult (questions[].options[].label + answers map). A custom
"Other" free-text answer is NOT a pick — falls through. Wired into
parseTranscript after the text-list detector.

#3 — parallel_session: dropped broad word matches (параллельн /
"parallel session") that false-fired on any casual mention. Now only
strong collision evidence (foreign git index / чужой staged /
index.lock / another git process). Best-effort per spec R2 — prefer
false-negative over false-positive.

169/169 tools tests GREEN (+9 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:39:09 +03:00
Дмитрий 287332eddf docs: CLAUDE.md header version drift fix — 2.18 -> 2.20
Header «Версия» line lagged at 2.18 while §9 already carried v2.19
(factor-analysis extension) and v2.20 (phase 1.1) entries — pre-existing
drift from f7f37fb. Header now reflects actual latest version; v2.18
summary demoted to «v2.18 наследие». Full per-version detail stays in §9.

Через /claude-md-management:claude-md-improver (§5 п.10).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:39:08 +03:00
Дмитрий f751ded65b docs(observer): implementation plan — phase 1.1 user_chose_from_options
5 tasks TDD plan with explicit code per step. Task 1 creates
observer-choice-detector.mjs pure module (23 tests). Task 2 wires
into transcript-parser. Task 3 extends routingGateDecision (no-block).
Task 4 extends brain-retro factor matrix. Task 5 normative sync
(Pravila §16.2 + CLAUDE.md §3.6 + spec cross-ref).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 11:53:53 +03:00
Дмитрий f7f37fb4e4 docs(brain): observer factor-analysis extension — normative sync
ADR-011 amended: +Decision §5 (observer v2 four-layer), §3 4→5
controllers (+C5), Enforcement +routing-gate + C5 bullets, related
+factor-analysis spec/plan.

Pravila v1.31→v1.32: §16.2 +абзац «Схема эпизода v2», §16.3 4→5
контролёров (+C5 row), +§16.7 routing-тег-дисциплина (mechanical
Stop-hook decision:block, stop_hook_active loop guard), +§16.8
самодисциплина наблюдателя (observer_error marker, parse_gap event,
C5 lefthook warn-only), §16.6 +cross-refs на factor-analysis spec/plan.

PSR_v1 v3.16→v3.17: R16.1 +предложение про schema v2 поля и
расширенные события; R16.4 +cross-refs.

Tooling Прил. Н v2.17: §0 cross-ref strings 1.31/3.16 → 1.32/3.17
(no header version bump).

brain-governance spec: related +factor-analysis spec.
observer-factor-analysis-design.md: status draft→accepted.

CLAUDE.md v2.19: §0 Pravila/PSR_v1 cross-refs bumped to v1.32/v3.17
with v2 summary prepended (legacy preserved as «v1.31 наследие» /
«v3.16 наследие»); §3.6 appended observer schema v2 + routing-gate +
C5 + brain-retro analyzer paragraph; §9 +v2.19 entry.

cross-ref-checker: 0 drift in 4 files.

Plan: docs/superpowers/plans/2026-05-19-observer-factor-analysis.md
Spec: docs/superpowers/specs/2026-05-19-observer-factor-analysis-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 11:08:55 +03:00
Дмитрий d484e60c46 docs(observer): brain-retro skill + README for schema v2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:55:37 +03:00
Дмитрий a6f44e5bb4 feat(observer): brain-retro analyzer — outcome inference + factor matrix
Pure deterministic Layer-4 aggregation module (spec §6) for the /brain-retro
skill. Exports: dedupeEpisodes, inferOutcome, groupEpisodesToTasks,
findCausalChains, buildFactorMatrix, analyze. Read-only — never writes JSONL.
11/11 tests green. CLI smoke: 10 real episodes → valid JSON with all 5 keys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 10:47:57 +03:00
Дмитрий 363357bff4 chore(observer): wire C5 coverage-checker into lefthook (job 15) 2026-05-19 10:44:10 +03:00
Дмитрий cde9478899 feat(observer): STATUS.md — C5 row + observer_error metric 2026-05-19 10:41:17 +03:00