# Безопасность разработки: изоляция чатбота от мультиагентов

## Проблема

InnerVoice (Telegram-бридж) запускает Claude для выполнения задач. Без изоляции задачи из Telegram могут конфликтовать с мультиагентами, работающими в worktrees, и сломать код на `main`.

## Архитектура: 5 слоёв защиты

### Слой 1: Git Worktree для чатбота

Персистентный worktree `/home/fitcrm-chatbot` на ветке `chatbot/workspace`. Все задачи чатбота и task manager работают в нём, а не в основном репо.

**Модуль:** `/home/innervoice/src/worktree-manager.ts`

| Функция                          | Описание                                                           |
| -------------------------------- | ------------------------------------------------------------------ |
| `ensureWorktree()`               | Создание worktree если не существует                               |
| `syncWorktree()`                 | Reset на `main` HEAD перед каждой задачей, проверка pnpm-lock.yaml |
| `getWorktreeCwd()`               | Возвращает `/home/fitcrm-chatbot`                                  |
| `isWorktreeReady()`              | Проверка существования и доступности worktree                      |
| `validateAndMerge(desc?)`        | Полный merge-протокол (см. Слой 4)                                 |
| `listRollbackTags(limit)`        | Список тегов `pre-chatbot-*` для отката                            |
| `rollbackToTag(tag)`             | Откат main на тег + рестарт PM2                                    |
| `cleanupOldTags(days)`           | Удаление тегов старше N дней                                       |
| `restartAffectedServices(files)` | Рестарт только затронутых PM2 процессов                            |

**Интеграция:**

- `chatbot.ts` — использует `getWorktreeCwd()` как CWD, вызывает `syncWorktree()` перед spawn
- `task-manager.ts` — аналогично + вызывает `validateAndMerge()` после завершения задачи
- `claude-spawner.ts` — если `project.path === '/home/fitcrm'`, подменяет на worktree
- `index.ts` — инициализация worktree при старте, очистка старых тегов

### Слой 2: Pre-commit хуки (husky + lint-staged)

Любой коммит (чатбот, агент, ручной) проверяется перед записью.

**Конфигурация:**

- `/home/fitcrm/package.json` — `lint-staged` секция
- `/home/fitcrm/.husky/pre-commit` — запускает `npx lint-staged`

**Правила lint-staged:**

```json
{
  "*.{ts,tsx}": ["eslint --fix --no-warn-ignored", "prettier --write"],
  "*.{js,jsx,json,md,css}": ["prettier --write"]
}
```

### Слой 3: Детекция конфликтов

Перед запуском задачи — проверка файлов, редактируемых в worktrees мультиагентов.

**Модуль:** `/home/innervoice/src/conflict-detector.ts`

| Функция                     | Описание                                         |
| --------------------------- | ------------------------------------------------ |
| `getActiveWorktreeFiles()`  | Сканирует 5 worktrees: diff + staged + untracked |
| `generateConflictWarning()` | Генерирует предупреждение для промпта Claude     |
| `checkFileConflicts(paths)` | Проверяет конкретные файлы на конфликты          |

**Сканируемые worktrees:**

| Worktree | Путь                   | Агент               |
| -------- | ---------------------- | ------------------- |
| backend  | `/home/fitcrm-backend` | Backend-разработчик |
| mobile   | `/home/fitcrm-mobile`  | Mobile-разработчик  |
| web      | `/home/fitcrm-web`     | Web-разработчик     |
| infra    | `/home/fitcrm-infra`   | DevOps              |
| tests    | `/home/fitcrm-tests`   | Тестировщик         |

Предупреждение вставляется в промпт Claude перед выполнением задачи.

### Слой 4: Протокол безопасного мёрджа

После завершения задачи в worktree (автоматически в task-manager):

**Две стратегии мёрджа:**

Документы (файлы в `apps/*/document/**`) — **быстрый путь:**

```
1. git status + git add -A + commit
2. git merge-base + diff — определение изменённых файлов
3. Все файлы в document/** ? → быстрый путь
4. git tag pre-chatbot-{timestamp} — точка отката
5. git rebase main — перебазирование (решает расхождение веток)
6. git merge --ff-only в main
7. pm2 restart fitcrm-web-platform-admin (только он)
8. git reset --hard main в worktree
```

Код (API, mobile, web, shared) — **полный путь:**

```
1.  git status + git add -A + commit
2.  git merge-base + diff — определение изменённых файлов
3.  Есть файлы вне document/** ? → полный путь
4.  pnpm lint — проверка качества
5.  pnpm --filter <app> typecheck — typecheck затронутых apps (tsc --noEmit)
6.  pnpm --filter api test — unit-тесты
7.  git tag pre-chatbot-{timestamp} — точка отката
8.  .deploy.lock — блокировка деплоя
9.  git rebase main — перебазирование
10. git merge --ff-only в main
11. Рестарт затронутых PM2 сервисов
12. git reset --hard main в worktree
13. Удаление .deploy.lock
```

Если lint/test провалились — Telegram-алерт, ветка сохраняется для ручного ревью.

**Маппинг файлов → PM2 процессы:**

| Паттерн файла              | PM2 процесс             |
| -------------------------- | ----------------------- |
| `apps/api/`                | `fitcrm-api`            |
| `apps/lp/`                 | `fitcrm-lp`             |
| `apps/web-admin/`          | `fitcrm-web-admin`      |
| `apps/web-club-admin/`     | `fitcrm-club-admin`     |
| `apps/web-platform-admin/` | `fitcrm-platform-admin` |

### Слой 5: Откат через /rollback

Команда `/rollback` в Telegram:

- Без аргументов — показывает список последних 5 тегов `pre-chatbot-*`
- С аргументом (тег) — выполняет `git reset --hard <tag>` на main + рестарт PM2 + sync worktree

## Конфигурация (.env InnerVoice)

```env
CHATBOT_CWD=/home/fitcrm-chatbot
TASK_CWD=/home/fitcrm-chatbot
CHATBOT_AUTO_MERGE=true        # Автоматический merge после задачи
CHATBOT_VALIDATE_LINT=true     # Проверка lint перед merge
CHATBOT_VALIDATE_TEST=true     # Проверка test перед merge
CHATBOT_AUTO_RESTART=true      # Автоматический рестарт PM2 после merge
```

## Верификация

1. Задача из Telegram работает в `/home/fitcrm-chatbot` (проверка: `pm2 logs innervoice | grep cwd`)
2. `git log` в `/home/fitcrm` не меняется во время выполнения задачи
3. После задачи — auto-merge (если lint+test прошли)
4. `/rollback` откатывает main на предыдущий тег
5. Коммит с ошибкой линтинга блокируется pre-commit хуком
6. Конфликтные файлы упоминаются в промпте Claude
