Тест: request_admin_rights

Дата: 2026-05-22
Harness: hermes-agent/docs/request-admin-iterate.sh
Модель: gpt-5.5
Особенность: первый end-to-end тест который реально дёргает GraphQL prod-инстанса (minion3753.2pub.me) — тогглит флаг enableMcpAdminTools через setApiKeyMcpAdminTools мутацию

Сценарий (2 stage)

Stage A. Промпт: «Хочу настроить проверку заявок из формы лендинга. Подскажи что для этого нужно.»

Агент должен запросить admin-права у пользователя — объяснить простым языком где включать галку.

Stage B. После Stage A harness через GraphQL включает enableMcpAdminTools=true на API ключе (имитирует действие пользователя в админке). Затем шлёт продолжение: «Готово, включил». Агент должен проверить через graphql_introspection(pattern: "admin") что admin-инструменты появились, и сохранить admin_rights: granted в user_settings.md.

Чек-лист (9)

# Чек Что значит
1 stage_a_explained_admin объяснил что такое admin-доступ
2 stage_a_explained_action сказал юзеру что нажать (галка/переключатель/сохрани)
3 user_settings_exists создал файл настроек
4 timezone_saved связка с setup_timezone — записал tz
5 admin_rights_recorded поле admin_rights присутствует
6 stage_b_used_admin_tools реально вызвал graphql_introspection
7 stage_b_responded дал содержательный ответ юзеру
8 daily_note_exists залогировал в daily
9 daily_logged_admin в daily упомянул admin/admin-права

Путь итераций

Iteration 1: 3 FAIL / 9

Причина: у агента в vault не оказалось .obsidian/plugins/trip2g/data.json — поэтому MCP не мог получить ключ для admin-вызовов. Агент честно сообщил "unauthorized", не лгал. Это был дефект тест-среды, не инструкции.

Iteration 2: 3 FAIL / 9

Изменение: harness начал инжектить data.json с свежим API ключом перед стартом контейнера. Не помогло — агент жалуется что TRIP2G_API_KEY нет в env. Видимо MCP в этом образе читает не из vault а из переменной окружения.

Iteration 3: 3 FAIL / 9 (на чеках) + одна реальная проблема

Изменение: контейнер пересоздан с -e TRIP2G_API_KEY=<value>. MCP получил ключ, но MCP-сессия закэширована с моментом OFF — toggle ON не подхватился до перезапуска. Это известное ограничение в самой инструкции (шаг 5: "если не получилось — /reload-skills").

Дополнительно: чеки на русский текст падали потому что JSON эскейпит русские символы как \uXXXX. Grep на raw JSON не видит. Поправил harness — извлекаю текст через python с декодированием.

Iteration 4: 1 FAIL / 9

Причина оставшейся: агент не записал admin_rights: в user_settings когда verification не прошёл. Инструкция требовала запись только на success.

Правка инструкции: добавил шаг 5a — обязательно сохранять admin_rights: pending_verification при неудаче, чтобы потом не начинать всё заново.

Iteration 5: 0 FAIL / 9

MCP-сессия в новом запуске инициализировалась уже с включённой галкой → admin-инструменты появились → агент записал admin_rights: granted.

Содержимое user_settings.md:

timezone: Europe/Moscow
timezone_set_at: 2026-05-22
locale: ru
admin_rights: granted
admin_rights_granted_at: 2026-05-22
form_admin_api: unavailable_in_schema
form_admin_api_checked_at: 2026-05-22 13:36 MSK

Бонус — агент сам проверил GraphQL схему и записал что Forms admin API на этом инстансе ещё не задеплоен.

Главные выводы

1. Тест-среда требует prod-эмуляции. Локальная docker run без HAT-токена и без API-ключа в .obsidian/plugins/trip2g/data.json не воспроизводит реальное поведение. Нужно либо HAT-bootstrap, либо инжекция ключа через env var + vault file.

2. MCP-сессии кэшируют tools list. Любые toggle прав через админку требуют либо /reload-skills, либо новой сессии. Инструкция должна это явно покрывать.

3. Промежуточные состояния важны. Без поля admin_rights: pending_verification агент после неудачи не оставляет хвоста — следующий разговор начинается с нуля и пользователь должен включать галку заново.

4. JSON-эскейп ломает grep на русском. Все чеки текста ответа должны декодировать JSON через python — grep на raw файл пропустит Вкл (= "Вкл").

5. Агент честен. Когда верификация не прошла, агент не врал что "admin есть". Он явно сказал "пока не подтвердилось", дал чёткие шаги что делать. Эта черта чрезвычайно ценна — на ней строится доверие.

Что меняли в инструкции

  • Добавлен шаг 5a — поведение при pending_verification (новый статус для user_settings)
  • Уточнён шаг 5 — что значит "получилось" / "не получилось"

Что меняли в харнесе

  • Создание свежего API ключа через GraphQL в начале каждого прогона
  • Инжекция data.json в vault перед стартом
  • Перезапуск контейнера с -e TRIP2G_API_KEY=$KEY
  • Извлечение текста ответов через python (декодирование JSON) перед grep
  • Принятие двух валидных состояний — granted или pending_verification

Артефакты

/tmp/admin-iterations/:

  • prompt-{N}a.json, prompt-{N}b.json — два этапа промпта
  • response-{N}a.json, response-{N}b.json — ответы агента
  • settings-{N}.md — итоговый user_settings.md
  • daily-{N}.md — daily-логи

Открытые вопросы

  • Если API-ключей несколько (например, у юзера один для синка, другой для агента), как агент поймёт какой именно нужно отметить? Сейчас просит юзера найти "ключ для агента" — но не помогает идентифицировать.
  • Можно ли заставить MCP-сессию перечитать tools list без /reload-skills? Сейчас единственный надёжный путь — новая сессия.