diff --git a/cspell-words.txt b/cspell-words.txt index 04c8a974..afe8cfc3 100644 --- a/cspell-words.txt +++ b/cspell-words.txt @@ -11,6 +11,13 @@ aitunnel захардкоженный захардкоженному эскейпы +роадмап +хардкод +хардкодами +askuser +роутинговой +роутингового +serialisation # Бренд и термины проекта лидерра diff --git a/docs/superpowers/specs/2026-06-12-router-mentor-roadmap.md b/docs/superpowers/specs/2026-06-12-router-mentor-roadmap.md new file mode 100644 index 00000000..52846a0f --- /dev/null +++ b/docs/superpowers/specs/2026-06-12-router-mentor-roadmap.md @@ -0,0 +1,68 @@ +# Роадмап эпика «роутер-наставник» — состояние на 2026-06-12 + +**Кодовая фраза:** «роутер-наставник». **Статус:** наставник АКТИВЕН и живой +(runbook Этап 4 пройден 2026-06-12, оператор API — aitunnel, commit `328ac009`). +Этот файл — единый список оставшихся работ эпика; вычёркивать по мере закрытия. + +## Идёт сейчас + +- [ ] **Этап 5 runbook — обкатка наставника (2-3 дня, владелец).** Смотреть вердикты + (по делу ли придирки) и траты в кабинете aitunnel. Шумно/дорого/«не туда» → + калибровка промпта (прецедент судьи `c9b9efd6`). + +## Главная стройка — Фаза 8 переезда М7 (одна большая сессия) + +Вход: новая сессия + «роутер-наставник», файл-вход handoff #5 +(`docs/superpowers/specs/...machine-7-build-handoff-5.md`, ветка `worktree-brainrepo`). + +- [ ] Тест-гейт §9.2 перед переездом. +- [ ] Регистрация М1-М6 в `.claude/settings.json` (шаг владельца — Claude файл закрыт). +- [ ] Увольнение v4-зоопарка (§10): старые enforce-хуки заменяются машинами. +- [ ] `sealedPlanCoversEdit` live + план отката. + +Фаза 8 попутно закрывает три известных занозы: + +- судья inert в основном репо → откроется печать планов и «зубы» freeze-gate + наставника (единственный непроверенный пункт Этапа 4); +- сломанный канал git-одобрений (`enforce-askuser-answer-parser` не пишет + `askuser-decisions-.jsonl` — обнаружено 12.06, коммитили вручную); +- зоопарковые `llm-judge-*` со своими хардкодами оператора уходят сами. + +## Шаг владельца (до или после Фазы 8) + +- [ ] **ИИ-проводка судьи М4** (пункт А памяти М7): реальный llm-транспорт в + `runJudgeGate` + флаг + обкатка shadow → block. Ключ `ROUTER_JUDGE_LLM_KEY` уже стоит. + +## После обкатки наставника (по очереди, отдельные согласования) + +- [ ] **Живой граф B** — снять маркер «КАРТА РАЙОНОВ ОТСУТСТВУЕТ» + (`graphSectionImpl: () => null` в `enforce-mentor-on-plan-write.mjs` → + parseGraph → buildDistrictMap → staleness). +- [ ] **E-S1** — производители «цель достигнута» (владелец/судья gate-3) для закрытия петли. +- [ ] **O9** — лимит доли INFERRED в проверенном контексте (спека §5.5, открытый вопрос). +- [ ] **VA-3-wiring** — дисциплина: при дозапросе района явно показывать пустую деталь («0 узлов»). + +## Мелкие хвосты (15-30 мин, любая сессия) + +- [ ] Хардкод proxyapi в `tools/observer-self-assessment-api.mjs:109` — тот же + env-фикс `ROUTER_LLM_BASE_URL`, что сделан транспорту 12.06 (модуль сейчас не активен). +- [ ] Исполнить smoke-план: поле «Связано:» в шаблон `docs/bugs.md` + (`docs/superpowers/plans/2026-06-12-smoke-mentor-stage4-bugs-template.md`). +- [ ] Memory-записи эпика: итог Этапа 4 + смена оператора aitunnel + сломанный + askuser-парсер (нужен ход с активным claude-md-management + `direct:memory-sync`). +- [ ] `/graphify --update` — граф помечен needs_update post-commit-хуком. + +## Вне эпика (отдельная тема, здесь только напоминание) + +- GitHub-аккаунт suspended → 305 локальных коммитов без пуша; до решения — + бэкап `git bundle create ... --all`. + +## Закрыто 2026-06-12 (для истории) + +- ✅ Runbook Этап 4 smoke: наставник end-to-end (вердикт wired:true, confidence 0.96, + binding plan_hash, журнал переговоров). +- ✅ 3 TDD-фикса: деталь ошибки транспорта в catch (`mentor-verdict.mjs`), + env `ROUTER_LLM_BASE_URL` в дефолте `callAnthropicAPI` (смена оператора), + контракт «массив строк» для `plan_points_addressed` в промпте (F-C3). +- ✅ Смена LLM-оператора proxyapi → aitunnel (env: base URL + 3 ключа), runbook-блок. +- ✅ Регрессия tools 3753 GREEN; commit `328ac009` на main. diff --git a/tools/observer-self-assessment-api.mjs b/tools/observer-self-assessment-api.mjs index 8e450c56..516379ae 100644 --- a/tools/observer-self-assessment-api.mjs +++ b/tools/observer-self-assessment-api.mjs @@ -147,7 +147,8 @@ export async function callSelfAssessmentApi({ actualNode, chainExecuted, apiKey, - baseUrl = DEFAULT_BASE_URL, + // Смена оператора 2026-06-12: env-переключатель в дефолте (зеркало callAnthropicAPI). + baseUrl = process.env.ROUTER_LLM_BASE_URL || DEFAULT_BASE_URL, model = DEFAULT_MODEL, fetchImpl, timeoutMs = DEFAULT_TIMEOUT_MS, diff --git a/tools/observer-self-assessment-api.test.mjs b/tools/observer-self-assessment-api.test.mjs index 062e4151..96aa2a4c 100644 --- a/tools/observer-self-assessment-api.test.mjs +++ b/tools/observer-self-assessment-api.test.mjs @@ -278,6 +278,18 @@ describe('callSelfAssessmentApi — request format', () => { expect(body.messages[0].role).toBe('user'); expect(body.max_tokens).toBeGreaterThan(0); }); + + // Смена LLM-оператора 2026-06-12: env ROUTER_LLM_BASE_URL переключает оператора + // и здесь (зеркало фикса callAnthropicAPI — модуль имел свой хардкод-дефолт). + it('ROUTER_LLM_BASE_URL env переключает дефолтный base URL (явный baseUrl не передан)', async () => { + process.env.ROUTER_LLM_BASE_URL = 'https://api.aitunnel.ru'; + try { + let capturedUrl; + const fakeFetch = async (url) => { capturedUrl = url; return { ok: true, json: async () => ({ content: [{ type: 'text', text: 'ok' }] }) }; }; + await callSelfAssessmentApi({ prompt: 'p', apiKey: 'k', fetchImpl: fakeFetch, timeoutMs: 5000 }); + expect(capturedUrl).toBe('https://api.aitunnel.ru/v1/messages'); + } finally { delete process.env.ROUTER_LLM_BASE_URL; } + }); }); // ---------------------------------------------------------------------------