# Рецепты восстановления

Справочник к навыку `ragraf-core`. Каждый рецепт — для состояния, которое уже
случалось в этом проекте или описано кодом. Порядок: диагностика, затем действие,
затем проверка результата.

## 1. Индекс устарел или «дрожит»

**Симптом.** Операция отвечает, но факты не совпадают с кодом; `freshness`
сообщает о расхождении; `check` повторяет реиндексацию при каждом вызове.

**Диагностика.**

```powershell
python tools/ragraf.py -p config/ragraf.yaml check
python tools/ragraf.py -p config/ragraf.yaml status
```

`check` сравнивает сумму корпуса с записанной в ревизии. Если суммы совпадают, а
`stale` не снимается, дело не в файлах, а в записи ревизии.

**Действие.**

```powershell
python tools/ragraf.py -p config/ragraf.yaml reindex
```

**Причина зацикливания, если оно повторяется.** Контрольная сумма обязана
считаться по тем же файлам, что попадают в индекс, и после схлопывания дублей
(`src/ragraf/corpus.py:59-70`, `:242-253`). Если схлопывание вынести в индексатор
или в сторож, сумма разойдётся с содержимым индекса и переиндексация не остановится.
Проверка на этот случай — `tools/Invoke-ProjectDoctrine.ps1`, правило о схлопывании.

## 2. Реестр показывает пустую ревизию и нули

**Симптом.** `python tools/ragraf.py catalog` для корпуса показывает `rev-` «нет»,
`nodes 0`, `edges 0`, хотя `status` того же корпуса сообщает ревизию и узлы.

**Причина (измерено).** Заведение корпуса через `ensure` регистрирует разработку до
индексации и результат прогона в реестр не записывает
(`src/ragraf/ensure.py:308-312`). Запись остаётся с триггером `register` и нулями.

**Действие — немедленный обход.**

```powershell
python tools/ragraf.py -p config/ragraf.yaml index
```

Этот путь пишет результат в реестр (`src/ragraf/cli.py:247`). Второй путь — любое
обращение, приводящее к работе сторожа: сторож записывает результат сам
(`src/ragraf/watch.py:554`). Подтверждение после действия — `catalog`: у записи
появляется ревизия, число узлов и рёбер и триггер вида `guard:fast`.

**Правильное исправление.** Добавить запись результата в `ensure` после успешной
индексации, вызывая `catalog.record_run` (`src/ragraf/catalog.py:235`) с числами из
прочитанной ревизии — так же, как это делает сторож. После правки:
`python tests/test_ensure.py`, затем повторный прогон чекера: правило о покрытии
реестра обязано позеленеть.

## 3. `capability=degraded`

**Симптом.** `index_status` сообщает `capability=degraded`, операция среза отказывает.

**Что это значит.** Слой свойств кода не построен или его экспорт не удался;
остальные слои (лексика, вектор, граф разбора) работают. Молчаливой деградации не
бывает: `src/ragraf/cpg.py:9-11`.

**Диагностика.**

```powershell
python tools/ragraf.py -p config/ragraf.yaml status
```

В стадии `cpg` будет записана причина. Известный случай на собственном корпусе:
экспорт вернул код 1, ошибка вида «next on empty iterator», при этом файл графа
свойств был построен. Причина не локализована — это дефект слоя, а не настройки.

**Действие.**

1. Убедиться, что Java и Joern доступны и расположены там, где их ищет код
   (`src/ragraf/cpg.py:82-93`, `:391`).
2. Перезапустить индексацию: слой строится заново.
3. Если отказ повторяется — работать без операций среза и записать находку
   отдельно; не выдавать `degraded` за поломку всего индекса.

**Важно.** Сервер Joern останавливается автоматически при закрытии индексатора
(`src/ragraf/indexer.py:1166-1183`). Незакрытый сервер — висящий процесс на гигабайты,
который держит порт; проверять список процессов после ручных экспериментов.

## 4. Правка исключений выбросила рабочий код

**Симптом.** Файлы, которые были видны в поиске, исчезли; ошибок при этом нет.

**Причина.** Сопоставление шаблонов регистрозависимо и понимает только шаблоны с
хвостом «любой каталог» для отсечения каталогов: `**/cache/**` ловит `src/cache/`,
но не `src/Cache/` (`src/ragraf/util.py:72-158`).

**Действие.**

```powershell
python tools/measure_safe_excludes.py     # сколько файлов выпадет по каждому корпусу
python tools/check_ragraf_config.py       # точность исключений собственного корпуса
python tools/check_service_excludes.py    # служебные каталоги не попадают в скан
```

Правило простое: если расширение базового списка выбрасывает ноль файлов во всех
корпусах — можно; если хоть один — имя идёт в конфиг конкретного корпуса, где видно
назначение каталога.

## 5. Схлопывание дублей и его цена

**Симптом.** Число файлов в индексе меньше числа файлов на диске.

**Что это.** Копии с одинаковым содержимым схлопываются, остаётся одна главная;
файлы на диске не удаляются. По умолчанию схлопывание выключено
(`src/ragraf/config.py:541`), и в конфиге собственного корпуса раздела с этими
настройками нет — значит на этом корпусе оно не применяется. Когда оно включено,
состояние индекса несёт счётчики отброшенного: сколько копий, сколько групп, байт и
строк (`src/ragraf/indexer.py:779-786`).

**Чего нельзя делать.** Менять правило выбора главной копии на «первую попавшуюся»:
ничья обязана разрешаться путём, иначе сумма корпуса дрожит и сторож зацикливается
(`src/ragraf/dedupe.py:165-223`).

**Проверка.**

```powershell
python tools/measure_dedupe_rules.py
python tests/test_dedupe.py
```

**Помнить.** Включение схлопывания меняет контрольную сумму корпуса: сторож один раз
переиндексирует корпус. Это осознанное следствие, а не дефект.

## 6. Вычислитель ушёл на процессор

**Симптом.** `index_status` сообщает процессорный вычислитель; время индексации выше
ожидаемого.

**Причины (по порядку проверки).**

1. Видеокарта выключена в настройках.
2. Объём работы ниже порога окупаемости: подготовка карты занимает около четверти
   минуты разово, поэтому на малом числе текстов она проигрывает
   (`src/ragraf/config.py:276-301`).
3. Не установлен пакет, требующийся карте: `sentence-transformers` и `torch` не
   объявлены в описании пакета (`src/ragraf/compute.py:141-146`).
4. Свободной памяти карты меньше порога — переход на процессор с причиной.

**Действие.** Смотреть поле `reason` в состоянии вычислений: там записана причина,
а не догадка. Понижать порог «чтобы карта работала» не нужно — это замедлит работу.

## 7. Панель администратора

```powershell
python tools/ragraf-admin.py --no-browser
```

Только локальный доступ, порт 8777, токен печатается при старте и выдаётся
странице отдельным запросом. Читающие запросы токена не требуют; любая правка
настроек — требует, пишется с резервной копией и проверкой ключей и границ
(`src/ragraf/settings.py:327-386`). Живые проверки панели:
`python tests/check_admin_agents.py` и `python tests/check_admin_dedupe.py`
(панель должна быть запущена).

## 8. Что делать при любом из состояний

1. Записать измеренное: команду, вывод, ревизию, сумму.
2. Отличить уже существующее состояние от последствия своей правки: baseline чекера
   записан в `AGENTS.md`, раздел 10 — **2 ошибок, 0 предупреждений**.
3. Не выдавать зелёный результат, не осмотрев объект: у каждой проверки в чекере
   есть счётчик осмотренных объектов, и ноль при успехе считается ложным PASS.
