7.2 KiB
tf_docs: код-ревью AI-ассистента и правки (поиск подресурсов + таймаут ЛЛМ)
Дата: 2026-10-12
Коммит: 12d29ee (репозиторий tf_docs, ветка master, запушен)
Контекст: по запросу — фактическое ревью кода/архитектуры ассистента с упором на ЛЛМ.
Что проверялось
Прочитан backend целиком: server.js, assist.js, search.js, stage1.js,
stage2.js, orchestrator.js; сверено с llm_project/docs/ASSISTANT_ARCHITECTURE.md
и результатами прогонов (llm_project/tests/RESULTS_*.json).
Найдено (факты, файл:строка на момент ревью)
- 🔴
search.js:206-215—resourceBaseSegmentперебирал суффиксы-подресурсы в исходном порядке, где_userстоит раньше_sub_user. Дляnubes_s3_sub_user(rest=s3_sub_user) отрезался_user→ bases3_subвместоs3. Следствие:isResourcePageне находила страницу ресурса ("s3_sub_user" !== "s3"), поиск поresource_typeдля*_sub_userбыл неэффективен. Реальный ресурс (есть вgolden_questions_300.json); эффект маскировался лексическим поиском по исходному вопросу. - 🔴
assist.js:25—ASSIST_LLM_TIMEOUT_MS(25 000) был объявлен вENVи задокументирован (README,ASSISTANT_ARCHITECTURE.md:§5), но нигде не использовался:orchestrator.jsне передавалtimeoutMsвstage1, аstage2Generateего не принимал. Фактически работал только общий дедлайн 40 с. - 🟡
orchestrator.js:205—clientIpбрал последний элементX-Forwarded-For(ближайший хоп) вместо первого (исходный клиент). Влияет только при заданномASSIST_TRUSTED_PROXY_CIDR(по умолчанию пусто). - 🟡
orchestrator.js:317,328— мёртвая ветка дедупа (handleAssistAgain— заглушка); в однопоточном JS недостижима. - 🟢 кэш ответов без TTL/лимита (
orchestrator.js:306);npm testпокрывает только прокси/health(LLM-пайплайн без юнит-тестов);fetchIndexбез лимита размера;FORWARD_HEADERSбезetag/last-modified; приabortedотдаётся нестандартный HTTP 499.
Исправлено (2 пункта)
1. search.js — порядок суффиксов подресурсов
Массив knownSubs вынесен в KNOWN_RESOURCE_SUBS, отсортирован по убыванию длины
при загрузке модуля. Проверено изолированно:
nubes_s3_sub_user → s3 (было s3_sub), nubes_mariadb_sub_user → mariadb;
nubes_postgres_database → postgres, nubes_postgres → postgres — без изменений.
2. assist.js + stage1.js + orchestrator.js — реальный per-call таймаут
llmChatполучил параметрtimeoutMs(дефолтENV.ASSIST_LLM_TIMEOUT_MS) и составной сигнал: дочернийAbortController, абортящийся по таймауту ИЛИ по аборту вызывающего. Таймаут покрывает вызов целиком (в т.ч. чтение тела).- Таймаут отдаётся отдельным кодом
llm_timeout(отмена клиентом/дедлайн — по-прежнемуaborted), чтобыstage2различал причины и корректно решал о повторе. stage1.jsосвобождён от дублирующегоAbortController.orchestrator.js:llm_timeout→ HTTP 504.
Проверено на локальном «зависшем» сервере: таймаут → llm_timeout (314 мс при
лимите 300), abort родителя → aborted (152 мс). node -c всех модулей OK,
node --test 4/4.
Проверка на живом стенде
redeployинстансаtf-docs(7a48a863-…) черезllm_project/tests/redeploy.js→ успешно (finish=2026-10-12T07:56:44+03:00,ok=true);/health→ 200.- Прогон 62 вопросов на
nubes-test(--out RESULTS_AFTER_FIX): 62/62 — 200 OK, шаблон 62/62, ошибок 0; задержки p50 5.9 с, p95 10.8 с, max 12.4 с;llm_timeoutне срабатывал ни разу. - ⚠️ Сравнение с прежним
RESULTS_LIVE.jsonнекорректно: тот от 2026-10-07, за 5 дней индекс документации изменился (у 45 из 62 вопросов другой набор источников) → это дрейф индекса, а не эффект правки.
Что НЕ менялось (осознанно)
Пункты 3–5 из «Найдено» (XFF, мёртвая ветка дедупа, кэш без TTL, юнит-тесты) — оставлены как есть: не мешают текущей работе; вернуться при масштабировании/переработке.
Режим «редактор файла» (добавлено в этой же сессии)
Новый эндпоинт POST /<stand>/_api/file (filemode.js): тело {content, instruction}
→ ответ {content, changes[], warnings[]}. LLM возвращает ПОЛНЫЙ обновлённый файл
(обычно terraform.tfvars). Опирается на текстовый search_index.json; секреты сюда
не кладут (отдельный secrets.auto.tfvars), логируются только размеры.
Следующий этап — требования (НЕ реализовано)
- Схемы заливать ВМЕСТЕ с документацией. В пайплайне публикации
(
TOOLS/scripts/04_build_and_publish_docs.sh) после сборкиsite/копироватьstack/<stand>/<svc>/raw.json→site/schema/<svc>.json, чтобыmc mirror(вscripts/publish-docs.sh) залил их в S3 наравне со страницами. Бэкенд берёт схему сVM_DOCS_BASE_URL/<stand>/schema/<svc>.json. (Сделано в этой сессии.) AGENTS.mdдля IDE-агентов — сделан вtf_provider(самодостаточный: структураraw.json, инвентарь 35 ресурсов, workflow, секреты, типичные ошибки).- MCP — отложен: требует ручной настройки у юзера в IDE (на этом этапе исключено);
ставка на zero-config
AGENTS.md+ режим/_api/file.