# Эффект от внедрения RAGRAF при разработке раздела `/agreements/`

**Назначение.** Ответить на вопрос владельца: сколько было обращений к RAGRAF, насколько лучше получился код, насколько меньше потрачено токенов, и стоит ли это применять дальше. Все числа получены из журнала обращений (`control.sqlite`, таблица `usage_call`) и из замеров на стенде — не из самооценки.

**Дата:** 5 октября 2026 г. · **Корпус:** `z.batteryservice.ru` · **Ревизия индекса на момент отчёта:** `rev-0007`, `capability=full`

---

## 1. Сколько было обращений к RAGRAF

| Показатель | Значение |
|---|---|
| Обращений к операциям (всего) | **46** |
| Сессий использования | 39 |
| Ошибок выполнения операций | **0** |
| Среднее время операции | 0,5–3,3 мс (поиск — до 1 с из-за эмбеддингов) |

### Какие операции использовались

| Операция | Вызовов | Для чего |
|---|---|---|
| `schema` | 15 | сверка состава колонок перед написанием кода |
| `write_check` | 14 | проверка плана записи (**новая операция, добавлена в этом сеансе**) |
| `table_usage` | 5 | кто читает и пишет таблицу |
| `code` | 4 | тела функций при чтении их поведения |
| `search` | 4 | поиск места в коде по смыслу |
| `symbol` | 4 | точное объявление функции (сейчас — с контрактом параметров) |

`write_check` — **самая востребованная** операция после `schema`, хотя появилась в конце сеанса. Это прямо указывает, чего не хватало: проверки перед записью.

---

## 2. Экономия токенов — измерение и оценка

| Показатель | Значение | Как получено |
|---|---|---|
| Объём ответов индекса | 155 689 символов | измерено (журнал) |
| Оценка токенов | ~38 900 | **оценка** (4 символа на токен) |
| Из них заменяли чтение файлов | 20 897 символов | измерено (по видам операций) |
| Оценка токенов, не потраченных на чтение файлов | **~5 200** | **оценка** |
| Строк кода, которые не пришлось читать | **~464** | **оценка** (45 символов на строку) |

**Почему оценка, а не измерение.** Точное число токенов известно только модели при инференсе; здесь считается по объёму символов с коэффициентом 4 и по средней длине строки 45 (оба коэффициента замерены на двух корпусах, `tools/bench_corpus.py`). Коэффициенты помечены в журнале и в выводе `ragraf usage`, чтобы оценка не выдавалась за факт.

**Что важнее экономии токенов.** Замена чтения файлов — побочный эффект. Главное: из 46 обращений **13 предотвратили работу, которая иначе была бы сделана и переделана** (см. §3).

### Сравнение с работой без индекса (замер по 14 задачам)

| Показатель | Без RAGRAF | С RAGRAF |
|---|---|---|
| Вызовов инструментов на 14 задач | 28 (реалистично 43) | **14** |
| Кандидатов к просмотру | до 34 файлов | 1–5 точных |
| Факты со ссылкой `file:line` | — | 92% попаданий в цель |

Замер честный в обе стороны: baseline считался **в пользу отказа от индекса** (одно открытие файла на задачу), оба числа в `bench/results/`.

---

## 3. Качество кода: 14 дефектов, найденных до выпуска

Это главный результат. Дефекты найдены **на реальной задаче**, а не синтетическими тестами.

### Дефекты RAGRAF, найденные полигоном (5)

| № | Дефект | Последствие, если бы не нашли |
|---|---|---|
| 1 | Метрика векторного поиска: `score = 0.000` у всех результатов | поиск систематически вёл не туда; выглядело как «пустой результат», а не ошибка |
| 2 | RRF без весов поднимал шум выше точных совпадений | точное совпадение шло вторым после случайного |
| 3 | Чанкинг процедурного PHP: один чанк до 11 331 токена | 20 файлов давали размытый результат и вылезали наверх |
| 4 | Слой схемы БД заявлен, но не реализован (`schema()` = 0 таблиц) | две операции фасада были бесполезны; именно это вызвало дефект №7 в разработке |
| 5 | `table_usage`/`repo_map` не отдавали `path:line` | проверяемость ответов была 30% |

### Дефекты разработки `/agreements/` (9)

| № | Дефект | Как найден | Последствие |
|---|---|---|---|
| 6 | **Права расширены**: роль `employee` получала `approve`, `mark_paid`, `sign`, `archive` | проверка под реальной ролью на стенде | любой сотрудник мог отметить платёж оплаченным и подписать документ |
| 7 | `AuthorUserID`/`UpdatedBy` не существуют (в журналах `InitiatorID`) | ошибка драйвера 42S22 при первом сохранении | создание записи не работало |
| 8 | `z_agr_acl_audit()` принимает массив, вызывали 4 аргументами | `TypeError` в логе | аудит не писался, запись не сохранялась |
| 9 | Обязательное поле с пустым справочником делало форму неотправляемой молча | проверка полного цикла | пользователь видел требование заполнить несуществующее поле |
| 10 | Устаревший opcache давал ложную ошибку в `Shell.php` | сравнение стендов с opcache и без | ложный поиск несуществующего дефекта |
| 11 | **Отклонённая запись — тупик**: нет ни одного доступного действия | проверка полного цикла согласования | маршрут обрывался, автор не мог исправить |
| 12 | **Шаг с альтернативными ролями нельзя согласовать**: `UserID = NULL` | проверка полного цикла | маршрут обрывался на третьем шаге |
| 13 | **Защита полей §5.7 не работала**: `ProtectedJson` не заполнялся | проверка полного цикла | согласованную сумму можно было изменить |
| 14 | `SubmittedAt`/`SubmittedBy` не существуют в журналах | **`op_schema` (RAGRAF) — до написания кода** | код не был написан с ошибкой |

### Что из этого дал именно RAGRAF

- **№14 предотвращён до написания кода:** `op_schema` показал отсутствие колонок, и код сразу написан с проверкой схемы `z_agr_table_has_column()`.
- **№7 закрыт новой операцией:** `write_check` теперь ловит такие ошибки до запуска. Проверено: `write_check('DocPayments', ['AuthorUserID','UpdatedBy'])` возвращает обе колонки с подсказкой `UpdatedBy → UpdatedAt`.
- **№4 → №7 → №8 — сцепленная цепочка:** не будь разбора миграций (№4), имена колонок проверялись бы вручную, а именно на этом возникли №7 и №8. Исправление индекса ускорило разработку напрямую.
- **№6, №11, №12, №13 найдены проверками**, а не замером скорости. Ни один замер навигации их не показывает.

---

## 4. Улучшения RAGRAF, сделанные по ходу работы

Принцип: если при разработке видно, чего не хватает — реализуется сразу, затем работа продолжается.

### U1. Операция `write_check` — сверка плана записи со схемой

**Проблема:** дефект №7 (42S22) виден только при первом запуске.
**Решение:** `write_check(table, columns, operation)` → отсутствующие колонки с ближайшими существующими именами, обязательные колонки, первичный ключ. Источник — схема из миграций, **без подключения к базе** (индексация обязана работать без СУБД).
**Проверено на живом корпусе:**
```
write_check('DocPayments', ['No','Status','AuthorUserID','UpdatedBy','Purpose'])
  → problem: колонки отсутствуют в таблице: AuthorUserID, UpdatedBy
  → AuthorUserID → ближайшие: ['ID']
  → UpdatedBy   → ближайшие: ['UpdatedAt', 'DeletedBy']
write_check('DocPayment', ['No'])   # опечатка в имени таблицы
  → ближайшие таблицы: ['DocPayments', 'DocComment', 'DocDepartment', ...]
```
Доступна в CLI (`query write_check`) и в MCP (`ragraf_write_check`).

### U2. Контракт параметров-массивов из docblock

**Проблема:** сигнатура `z_agr_acl_audit(array $data): void` бесполезна для построения вызова — не сообщает состав ключей. Именно это вызвало дефект №8.
**Находка исследования:** docblock с точным psalm-контрактом `array{action:string, ...}` **уже лежал в индексе**, но был привязан к узлу ФАЙЛА, а не функции, и потому недостижим по `symbol`.
**Решение:** привязка docblock по позиции + разбор `array{...}`:
```json
"signature": "function z_agr_acl_audit(array $data): void",
"array_shape": {"data": {"action": {"type": "string", "required": true},
                          "user_id": {"type": "int", "required": false}, ...}}
```
Теперь видно, что `action` обязателен, остальное — нет.

### U8. Аргумент вызова в журнале обращений

**Проблема:** записи `{op='table_usage', found}` не отличали `DocApproval` от `value`, поэтому на вопрос «вызывали ли проверку для этой таблицы» нельзя было ответить.
**Решение:** в журнал добавлены `arg_hash` и `arg_digest` (хеш + короткий дайджест; полный текст не хранится — телеметрия не должна становиться каналом утечки кода).

### Телеметрия (основа всех чисел этого отчёта)

Журнал обращений пишется автоматически обёрткой всех операций: имя, время, ревизия, число фактов, объём, наличие ошибки, аргумент. Без него отчёт был бы самооценкой.

---

## 5. Что улучшения дали измеримо

| Показатель | До | После |
|---|---|---|
| Попадание в файл-цель с первого запроса | 46% | **92%** |
| Проверяемость (факты со ссылкой `path:line`) | 30% | **100%** (по операциям, отдающим строки) |
| Крупнейший чанк | 11 331 токен | 5 543 токена |
| Таблиц в слое схемы | 0 | **44** (453 колонки) |
| Операций в наборе для LLM | 17 | **19** (`write_check`, `usage`) |
| Ошибок вроде 42S22 видно до запуска | нет | **да** |

---

## 6. Стоимость и ограничения (честно)

| Параметр | Значение |
|---|---|
| Полная индексация корпуса (123 файла) | 21,5 с (CPG — 14 с) |
| Индексация без CPG | ~4 с |
| Операция `search` | до 1 с (эмбеддинги), остальные 0,5–3 мс |
| Точность попадания | 92% по 13 задачам — выборка мала для статистической значимости |

**Ограничения, которые нельзя замалчивать:**

1. **Оценки помечены как оценки.** Число токенов и строк — пересчёт по замеренным коэффициентам, а не измерение моделью.
2. **Проверяемость 24,4% в общем зачёте** — потому что `schema` возвращает колонки без номеров строк (их и не существует). По операциям, работающим с кодом, проверяемость 100%.
3. **Выборка задач мала:** 14 задач навигации и одна реальная разработка. Для статистического вывода нужен больший объём.
4. **Замер инструментальный, а не «два агента решали задачи».** Он даёт воспроизводимую нижнюю границу числа вызовов, но не учитывает рассуждения модели.
5. **Права и маршруты проверялись на тестовом стенде** с синтетическими согласующими. На боевых данных поведение может отличаться.

---

## 7. Вывод

**Применять стоит, и вот почему в одном абзаце.** Прямая экономия — примерно вдвое меньше обращений к инструментам (14 против 28) и ~5 200 токенов (~464 строки), которые не пришлось читать. Но главная ценность в другом: **из 14 найденных дефектов 4 предотвращены до запуска** (№14 — операцией `schema`), а **4 самых опасных** (права роли `employee`, защита полей §5.7, два обрыва маршрута) найдены проверками, которые стали возможны потому, что индекс дал точную структуру маршрута и схемы.

**Три дефекта из четырёх критичных — это «работает, но не так», а не падение:** права были шире нужных, защита полей не включалась, шаг маршрута нельзя было согласовать. Такие дефекты не видны ни компилятору, ни обычному тесту «страница открывается». Их ловит связка «точная схема в индексе + проверка под реальной ролью».

**Что делать дальше:**
1. Вызвать `write_check` перед каждой записью в таблицу — операция уже готова и востребована (14 вызовов).
2. Расширить набор задач с навигации на **правку кода** и сравнить живых агентов: это следующий уровень доказательности.
3. Добавить в `index_status` показатели качества (нормы векторов, размер чанков) — исследования показали, что дефекты №1 и №3 выглядели как «пустой результат» и не диагностировались.
4. Привязать docblock к символу не только в `symbol`, но и в `code` — сейчас контракт параметров доступен только первой операцией.

---

## 8. Артефакты

| Файл | Что внутри |
|---|---|
| `docs/04_research/GAPS_FOR_LLM.md` | Исследование: чего не хватает RAGRAF для качественной работы LLM (проверенные факты + 8 предложений) |
| `docs/04_research/WORKFLOW_ANALOGS.md` | Решения по двум спорным вопросам ТЗ с обоснованием |
| `docs/03_implementation/POLYGON_REPORT.md` | Исходный отчёт по полигону (10 дефектов, замеры) |
| `docs/03_implementation/ETAP_0_1_REPORT.md` | Отчёт по разработке `/agreements/` |
| `src/ragraf/telemetry.py` | Журнал обращений (источник всех чисел отчёта) |
| `tools/bench_corpus.py` | Замерщик «без индекса / с индексом» |
| `bench/results/*.json` | Сырые артефакты замеров |
