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>
Реальный портал отдаёт 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)) сходится с фактом)
Портал 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>
План 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) без регрессий.
План 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).
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>
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>
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>
#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>
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>