# WORKLOG — do_it

**Updated:** 2026-04-23

---

## Спринт 3 — выполнено (2026-04-19)

Все задачи S3-T1..T8 закрыты. Дополнительно закрыты три дефекта найденных аудитом.

---

## Сессия 2026-04-21 — T1..T3 тесты + три production-бага

### B1 — Telegram принимает stale-сообщения ✅
### B2 — TUI prompt не появляется ✅
### B3-diag — AWP tracing ✅

Подробности в предыдущих версиях.

---

## Сессия 2026-04-22 — разбор bug_7 (4 бага из реального запуска)

### B7-1 — check.rs: ws:// отклоняется как неверный URL ✅

**Файл:** `src/start/check.rs`

**Диагноз:** Проверка AWP URL схемы принимала только `http://` и `https://`,
хотя AWP — WebSocket протокол и корректная схема — `ws://` / `wss://`.
`AwpClient::new()` уже поддерживает оба варианта.

**Исправление:** Условие расширено: принимаются `ws://`, `wss://`, `http://`, `https://`.
Сообщение об ошибке обновлено. Добавлены два unit-теста: `awp_ws_scheme_is_valid`
и `awp_invalid_scheme_is_rejected`.

**Верификация:** cargo test — зелёный.

---

### B7-2 — TUI prompt не показывается при вопросе субагента ⚠️ АНАЛИЗ

**Диагноз из лога:**

Лог строки 12/18/27: `ask_human Telegram poll failed: 409 Conflict`.
Telegram возвращает 409 — значит параллельно работает второй экземпляр getUpdates.
Это inbox_poller из предыдущей сессии (не завершённый) + ask_human из текущей.

Дополнительно: субагент (depth > 0) не имеет TUI handle напрямую —
TUI handle хранится в boss-агенте. Субагент получает handle через `self.tui()` что
возвращает `None` если субагент создан через `spawn_agent`. Проверить нужно
`agent::spawn.rs` — как именно передаётся tui handle субагентам.

**Итог:** два независимых фактора:
1. 409 Conflict = два экземпляра getUpdates (inbox_poller + ask_human)
2. Возможно субагент не получает TUI handle → popup не отправляется

Требует отдельного исследования.

---

### B7-3 — ответ "no" игнорируется ⚠️ АНАЛИЗ

**Диагноз из лога:**

Boss порождает субагента (строка 7), тот получает 2 ошибки navigate,
пытается ask_human → Telegram 409 → ask_result = Err → should_continue = false
→ субагент завершается с сообщением об ошибке.

Boss получает строку результата от субагента (не Err, а Ok с текстом ошибки)
→ не видит причины останавливаться → порождает ещё одного субагента.

Это поведение boss: он не интерпретирует содержимое результата субагента.
Это не баг кода `ask_human`, а поведение boss-промпта или логики run_capture.

**Требует:** либо boss-промпт должен явно обрабатывать "exited due to errors",
либо нужен механизм передачи stop-сигнала от субагента к boss.

---

### B7-4 — browser_navigate падает с file:// URL ⚠️ ОГРАНИЧЕНИЕ

**Диагноз из лога plasmate:**

```
Navigating (full pipeline) url=file:///D:/test/check/xon1/index.html
Session closed session_id="s_0f52f312"
```

Plasmаte — HTTP-сервер. Он делает HTTP GET на URL. `file://` — не HTTP.
Сервер возвращает ошибку `NAVIGATION_FAILED` → `browser_navigate` падает.

AWP протокол (секция 4.4) явно описывает только HTTP GET с cookie jar.
`file://` не упомянут и не поддерживается.

**Решение для пользователя:** использовать HTTP сервер для локальных файлов.
Например: `python -m http.server 8080` или plasmate встроенный file server (если есть).
Тогда URL будет `http://127.0.0.1:8080/index.html`.

**Требует:** добавить в prompt браузерных инструментов явное предупреждение
что `file://` не поддерживается — нужен HTTP URL.

---

## Сессия 2026-04-23 — B8-1 + B7-2-fix

### B8-1 — browser_action: явная ошибка когда url не передан ✅

**Файлы:** `src/tools/browser.rs`, `src/tools/spec.rs`

**Диагноз:** Агент вызвал `browser_action` без `url`. AWP сессии stateless — каждый вызов
инструмента открывает новое соединение с чистой сессией, страница не загружена.
Без навигации `page.act` падал с `NOT_FOUND: No page loaded yet` — криптичная ошибка
сервера. Теперь `bail!` срабатывает до открытия соединения с явной диагностикой и примером.

**Дополнительно:** `div.cell` без ARIA-роли не видны в SOM — это нормальное ограничение
AWP v0.1. Нужен `css=` target. Добавлен комментарий в код и обновлён prompt_line.

**Исправления:** `browser.rs` (ранняя проверка + тест `action_rejects_missing_url`),
`spec.rs` (prompt_line: url обязателен, примечание про css= для non-ARIA элементов).

**Верификация:** `cargo test -p do_it -- tools::browser`

---

### B7-2-fix — TUI popup субагента не появляется ✅

**Файлы:** `src/tools/human.rs`, `src/agent/spawn.rs`

**Диагноз (полный):**

Цепочка: boss запускает `spawn_agent` → `SweAgent::new_with_depth(depth+1)` создаётся
с `tui: None`. В `step()` и `run_capture()` TUI callbacks устанавливаются только если
`self.tui().is_some()` — для субагента всегда `None`. Callbacks остаются `None`.

Когда субагент вызывает `ask_human`: `tui_is_active()` == `true` (глобальный флаг),
но `tui_ask_send()` возвращает `None` (нет callbacks) → субагент идёт в
"wait only for Telegram" → 409 Conflict от inbox_poller.

**Решение:**
1. `human.rs` — добавлена `pub fn install_tui_callbacks_from_tx(tx: UnboundedSender<TuiEvent>)`
   — устанавливает TUI callbacks из raw sender без TuiHandle. Дублирует логику
   `install_tui_callbacks` из `loops/mod.rs` но принимает только `tx`.
2. `spawn.rs` — перед `sub_agent.run()`: читает `tui_sender()` (уже установленный
   родительским `step()`) и вызывает `install_tui_callbacks_from_tx`. После
   `sub_agent.run()` очищает callbacks и Telegram config.
3. `spawn.rs` — добавлен тест `test_tui_callbacks_cleared_if_no_sender`.

**Верификация:** `cargo test -p do_it -- agent::spawn`

---

## Сессия 2026-04-30 — архитектурный баг scripting_guide

### B9 — scripting_guide.md не инжектировался в промпт ✅

**Файлы:** `src/tools/spec.rs`, `src/agent/prompt.rs`

**Диагноз:** `scripting_guide.md` существовал с самого начала проекта но никогда не
подключался к промпту. Агент видел только одну строку `prompt_line` с перечнем функций.
Синтаксис Rhai, host-функции, лимиты, паттерны использования — всё это агент не знал.
Этим объясняются все ошибки агента при работе с `run_script`.

**Исправление:**
1. `spec.rs` — `pub const RUN_SCRIPT_GUIDE: &str = include_str!("scripting_guide.md")`
   загружает guide в compile time, без runtime I/O и drift.
2. `prompt.rs` — `build_prompt` инжектирует guide после основного промпта,
   только для ролей у которых `run_script` в allowlist
   (developer, navigator, qa, default). Boss, reviewer, research — не получают.

**Тесты:**
- `build_prompt_includes_scripting_guide_for_roles_with_run_script`
- `build_prompt_excludes_scripting_guide_for_roles_without_run_script`

**Верификация:** `cargo test -p do_it -- agent::prompt` — зелёный.

---

### Аудит boss.md + остальные промпты ✅

**Файлы:** `src/prompts/boss.md`

**Находки:**
1. Ручной блок `### Browser` в `boss.md` содержал устаревшую сигнатуру
   `browser_action(action, selector, value?, wait_ms?)` — исправлено на
   `browser_action(action, url, ref?, css?, value?, wait_ms?)` (соответствует B8-1 fix).
2. `browser_navigate` в том же блоке и в workflow-описании не имел предупреждения
   о `file://` — добавлено (согласовано с B7-4-doc).
3. Остальные промпты (developer, navigator, qa, reviewer, research, memory) —
   расхождений не найдено. Секции `## Available tools` в них перезаписываются
   через `inject_tool_catalog_with_groups` при загрузке, поэтому актуальны автоматически.
   Тест `non_default_role_prompts_only_advertise_allowed_tools` — зелёный.

**Верификация:** `cargo test -p do_it -- config_struct::tests` — зелёный.

---

## Следующие шаги

---

### Интеграционный тест B7-3-fix ✅

**Файлы:** `src/agent/spawn.rs`, `tests/integration/spawn.rs`, `tests/integration/main.rs`

**Суть:** Вынесена `pub async fn build_result_text(memory_key, root, role_name)` из
`spawn_agent` для тестируемости без LLM. Написаны 5 интеграционных тестов против
реального файлового memory-store (tempdir), без агентного цикла:
- `stopped_by_user_in_memory_produces_failure_text`
- `exited_due_to_repeated_errors_in_memory_produces_failure_text`
- `normal_completion_in_memory_produces_success_text`
- `no_memory_key_produces_success_text`
- `unwritten_memory_key_produces_warning_not_failure`

**Верификация:** `cargo test -p do_it --test integration spawn` — зелёный (5/5).

---

## Следующие шаги

Открытых дефектов нет. Кандидаты по приоритетам проекта:

1. **Safety/policy controls (приоритет 2)** — аудит `loop_policy.rs` ✅
2. **Memory/state hygiene (приоритет 3)** — аудит lifecycle ✅
3. **Observability/replayability (приоритет 4)** — `args_preview` в трейсе, `schema_version→4` ✅
4. **Regression test depth (приоритет 5)** — расширены интеграционные тесты memory (4 новых теста), исправлен устаревший assert schema_version в session.rs. ✅
5. **Docs/code consistency (приоритет 6)** — аудит `DOCS.md`: исправлена таблица memory-ключей, сигнатура `browser_action`/`browser_navigate`. ✅
6. **Repo hygiene (приоритет 7)** — аудит корня репозитория. ✅
   - `awp-mvp.md` перемещён в `docs/awp-mvp.md`.
   - `.gitignore` дополнен `*.log` (раньше `awp.log` попал бы в репозиторий).
   - Известные остатки (удаление недоступно через Filesystem MCP):
     - `src/tools/utils.rs_` — мёртвый черновик re-экспортов, не компилируется, удалить вручную.
     - `qodana.yaml` — незаполненный шаблон (`linter: jetbrains/qodana-<linter>:2026.1`), удалить вручную.
     - `.github/agents/` — пустая директория, удалить вручную.
7. **Новый баг из реального запуска** — если есть свежие логи.

---

## Архитектурные константы

- `src/tools/scripting_guide.md` — единственный источник правды о Rhai: синтаксис,
  host-функции, лимиты. Инжектируется в промпт через `RUN_SCRIPT_GUIDE` через `build_prompt`
  только для ролей с `run_script` в allowlist. Не дублировать содержимое
  в `spec.rs` `prompt_line` для `run_script`.
- `src/tools/spec.rs` — единственный источник правды по инструментам.
- `src/tools/memory.rs` reserved keys: last_session, plan, external_messages,
  user_profile, boss_notes, tool_wishlist.
- AWP: close = session.close + WebSocket Close frame + дрейн до Close от сервера.
  page.observe возвращает `{ "som": {...} }` — поле "som" обязательно.
  page.act target: `{"ref": "e_xxx"}` или `{"css": "selector"}`, не `{"selector": ...}`.
  with_session = одно соединение на вызов инструмента. Агент ОБЯЗАН передавать
  url в каждый вызов browser_action — сессия stateless, страница не сохраняется.
  AWP НЕ поддерживает file:// — только http:// и https://.
  awp_url принимает ws://, wss://, http://, https://.
  AWP SOM содержит только элементы с ARIA-ролями. div/td/span без роли
  НЕ видны в SOM — использовать css= target для таких элементов.
- is_affirmative_response(): yes/y/да/д/continue/ok/продолжай/proceed/go.
  TUI callbacks сбрасываются ВСЕГДА после ask_human, независимо от ответа.
- run_script timeout: 30s (tokio::time::timeout).
- fnv64() в Rhai — FNV-1a 64-bit, не криптографический хеш.
- drain_pending_updates() вызывается перед каждым ask_human вопросом в Telegram.
- AskSendFn: отправляет TuiEvent::Prompt немедленно, возвращает Receiver.
- AWP tracing: RUST_LOG=do_it::tools::browser=debug.
- Telegram 409 Conflict: возникает когда inbox_poller и ask_human одновременно
  вызывают getUpdates. Предыдущая незавершённая сессия тоже может оставить
  hanging getUpdates — нужно убедиться что inbox_poller всегда останавливается.

