1. Phase64 — телеметрия эпизодов подбора расценок (админ-аналитика + outcome)

— Backend admin: AdminChatAnalyticsController — проксирует /api/admin/chat-analytics/* (summary, episodes, episodes/{id}) на agent под admin JWT (AgentEvalClient).

— Frontend admin: новая страница /admin/chat-analytics (ChatAnalyticsView.vue, 285 строк) — дашборд (accept-rate, исходы, подборы по моделям), список эпизодов с фильтрами (исход/режим/эксперт/поиск, «только ошибки»), карточка эпизода (вход → кандидаты с signals/каналами → рекомендация vs выбор → токены/стоимость/латентность). chatAnalyticsApi + роут + пункт меню.

— Backend user: EpisodeOutcomeController — POST /api/chat/episode/{id}/outcome (chosenCode, chosenRank, outcome?) проксирует на agent, best-effort.

— Frontend user: при выборе кандидата фронт шлёт chatApi.episodeOutcome (rank=1 → accept_top1, иначе choose_other), episode_id из события rascenka_candidates.

— Файлы: AdminChatAnalyticsController.java, ChatAnalyticsView.vue, EpisodeOutcomeController.java, ChatWorkspaceView.vue, RascenkaCandidates.vue.

2. Phase63 — обратный индекс «материал → расценки», новый канал в чате

— GET /api/agent/fsnb/raboty-by-material?code=|?name= → {matched_materials, direct[], via_tg[{tg_code, tg_name, materials, raboty}], total_raboty}.

— direct: resurs_v_rabote WHERE resurs_code IN (коды); via_tg: материалы → ТГ (tg_resurs, дедуп) → расценки через abstract_resource.rabota_id WHERE technology_groups = tg.code. Матч точным равенством по technology_groups (не LIKE), дедуп расценок по коду (6 версий ФСНБ = 1).

— Резолв name → resurs по nazvanie, группировка через ТГ (типоразмеры схлопываются).

— Проверено: code 01.6.04.03-0001 → ТГ 28.13.048 → 15-07-021-01; name «плинтус потолочный» → 20 матов → 1 ТГ → 1 расценка.

— Файлы: CatalogService.java (+119 строк), AgentFsnbController.java, docs/material-search-channel-stub.md.

3. Phase66 — материал в ВОР (строка-материал + поиск + кандидаты в чате)

— A1 backend: GET /api/agent/fsnb/material/search?q=&fsnbId= — поиск по справочнику ФСБЦ_Мат&Оборуд без split_forma, БЕЗ цены (ВОР-фаза), JOIN sbornik_fsnb по tip=’ФСБЦ_Мат&Оборуд’+fsnb, ILIKE по kod/name. Guard X-Service-Token.

— C frontend: ВОР (VorRabotaWithMappings) — дочерние строки-материалы из fsnb_mapping.materials[], зелёный акцент, бейдж «📦 Материал», сквозная нумерация, видны до генерации, удаление через vor_rabota_update без материала. Каретка раскрытия учитывает и расценки, и материалы.

— C чат: RascenkaCandidates переиспользован под материалы (prop kind=’material’), ChatWorkspaceView ловит SSE material_candidates → карточки kind=material; onSelectMaterial шлёт «Выбираю материал {code}… Добавь как неучтённый».

— C fix: материал-кандидаты приходят тем же rascenka_candidates, candKindOf() различает по форме (resurs_code=материал vs fsnb_code=расценка).

4. Phase61/62 — дерево ancestry и каталог осей ФСНБ из БД

— Phase61: fsnb_rabota_get отдаёт полный ancestry — рекурсивный CTE по razdel.parent_id (самоссылочный, phase59), levels + tip + gruppa + rabota + path-строка + inherited_chars (через FsnbCharacteristicService.getByCode, source=inherited_from_*). Цикл бинов разорван @Lazy. Проверено: 15-01-019-05 → ГЭСН › Отделочные › Облицовочные › Облицовка плитками.

— Phase62: GET /api/agent/fsnb/characteristics/axes — оси из БД (koef_characteristic_meta, applicableToFsnb, active) вместо статического канона из кода (5 осей → 11 актуальных). Старый путь оставлен для agent eval/canon.py.

5. UX сметы — комментарий к работе, иконки/колонки, неучтённый ресурс

— Backend: новая колонка smeta_rabota.comment (text); PUT /smeta/rabota/{id} {comment} (null=не трогать, «»=очистить); агент может задавать при создании и через PUT. Флаги hasSelectableMaterials и hasUnfilledPrQnt считаются batch-SQL (один запрос на смету), проверены на TEST.

— Backend: NeuchtennyyResursResponse.sbornikTip для не-ручного ресурса (CatalogService.lookupResursSbornikTip: resurs→sbornik_fsnb.tip), чтобы фронт показывал строку как работу (бейдж + код).

— Frontend smeta: добавлены 2 колонки слева (иконки 🧱/⚠ + действия: характеристики/💬 комментарий/✕ удалить), сетка 12→14 колонок (g-col-icon 28px + g-col-action 54px), nth-child сдвинуты на +2, синхронизация с заголовком и адаптивами 900/600px.

— Frontend smeta: колонка № разделена на «раскрыть» (шеврон) + «номер», сетка 14→15.

— Frontend smeta: строка неучтённого ресурса раздела приведена к виду работы (бейдж сборника/Ручной + код, кнопка удаления во второй колонке).

6. Чат — карточка расценки-варианта и шлифовка trace

— Backend: GET /api/catalog/rabota/by-code/{kod} — резолвит id (активная/последняя версия ФСНБ) → getRabota, для деталей кандидата (у кандидата есть код, не numeric id).

— Frontend: клик по коду/названию кандидата или кнопка «🔍 детали расценки» открывает VorFsnbCard прямо в чате по коду; любое новое сообщение скрывает прошлые карточки вариантов (onSend фильтрует role===’candidates’).

— Frontend trace: переписан под обновлённый контракт signals — 9 каналов (🔍 material_search новый, 🌳 tree_context с path/note/inherited, 🧠 kb_expert без weight, 🌐 web с warn/mut, 🔤 fts, 🏷 characteristics, unit/material/sostav). Все 9 каналов рендерятся всегда, пустые — статусом. Добавлен фолбэк на note для характеристик/дерева/fts/web.

7. ВОР — автоскролл и точечные обновления из чата

— flashRow (точечное обновление по entity_updated) теперь, помимо подсветки, делает scrollIntoView({block:’center’}) к изменённой строке; ждёт появления строки в DOM до 5 кадров (requestAnimationFrame).

— Убран полный reloadVor() на tool_result агента для vor_rabota_add/update/delete — конфликтовал с точечным entity_updated, сбрасывал скролл и уничтожал подсвеченный узел. Полный reload оставлен только для групп/ВОР, где точечного события нет.

— Fix: «Выбрать» в ручном режиме наполняет ВОР, не смету — текст user-сообщения изменён на «…Добавь её в ведомость объемов работ» (парная к agent-фиксу ff5a396).

Сводная статистика по коду:

Проект | Добавлено строк | Удалено строк | Коммитов

smeta_admin_backend | 89 | 1 | 1

smeta_admin_frontend | 296 | 1 | 1

smeta-user-backend | 510 | 12 | 9

smeta_user_frontend | 493 | 143 | 14

Итого | 1388 | 157 | 25

Оценка трудозатрат:

Задача | ~Часы

Phase64 — телеметрия эпизодов (admin дашборд + outcome) | 5

Phase63 — обратный индекс материал→расценки (SQL + ТГ) | 4

Phase66 — материал в ВОР (backend поиск + frontend строка/чат) | 5

Phase61 — ancestry в fsnb_rabota_get (рекурсивный CTE + inherited) | 3

Phase62 — каталог осей ФСНБ из БД | 1.5

UX сметы — иконки/колонки/комментарий/неучтённый ресурс | 4

Чат — карточка расценки по коду + 9 каналов trace | 3

ВОР — автоскролл и точечные обновления | 2

Итого | ~27.5 час