# Запрос к Sonnet: анализ обфускации **Дата:** 2026-07-13 --- **Задача:** Найти причину расхождения между ожидаемыми кодами замен и реальными заменами. ## Ожидаемое поведение `_next_token()` в `drhider/scanner.py` генерирует коды замен формата: - `Технология_0001`, `Прогресс_0002` (для компаний) - `+7_000_000_0001` (для телефонов) - `email_0001` (для email) - `ИНН_0001` (для ИНН) - `Иванов_0001` (для ФИО) ## Реальный результат — `TMP/mapping.csv` ``` тип_данных,оригинал,замена phone,+7 (495) 789-41-35,+7 (495) 906-87-80 ← НЕ код замены, реальный номер email,info@nubes.ru,ypiorej@company.local ← НЕ код замены, реальный email company,ЗАО ****XXX****001****,АО «Прогресс» ← НЕ код замены, реальное название company,ЗАО XXX001,ООО «Альянс» ← НЕ код замены, реальное название inn_ul,ИНН 9706005293,ИНН 1846691249 ← НЕ код замены, реальный ИНН kpp,КПП 772401001,КПП 350443068 ← НЕ код замены, реальный КПП ks,Кор/сч 30101810400000000225,Кор/сч 30101201490272090211 ← НЕ код замены ogrn,ОГРН 1207700098759,ОГРН 1048672318430 ← НЕ код замены company,ООО "НУБЕС",ООО «Спектр» ← НЕ код замены text,Исполнителем Заказчику Сторонами,Кузнецов О.В. text,"Обязанности Заказчика\nСвоевременно",Степанов А.В. text,"Обязанности Исполнителя\nОказывать",Петров П.Е. text,"Ответственность Заказчика\nЗаказчик",Новиков А.М. text,"Ответственность Исполнителя\nИсполнитель",Попов О.М. company,ПАО Сбербанк,АО «Формат» ``` **Ни одного кода замены формата `XXX_0000` в колонке «замена».** ## Реальный результат — `TMP/договор-XXX001-03700_obfuscated.md` (первые строки) ```markdown **АО «Прогресс»** ... и **ООО **"**НУБЕС**" ... Новиков И.В. ... ``` - `Новиков И.В.` — НЕ заменён (должен быть `Иванов_0001`) - `ООО "НУБЕС"` — НЕ заменён в тексте (есть в mapping но замена не применена?) - `г. Москва, 1-я Стекольная 7с5` — адрес не заменён ## Файлы для анализа **Обязательно прочитать:** 1. `drhider/scanner.py` — `_next_token()`, `scan_regex()`, `scan_llm_ner()`, TYPE_POOLS, промпт LLM (строки 109-151) 2. `drhider/obfuscator.py` — порядок вызова regex → LLM, как объединяется mapping (строки 63-95) 3. `drhider/config.py` — ENTITY_PATTERNS, COMPANY_PATTERN, PERSON_PATTERN 4. `drhider/llm_client.py` — `LLMClient.complete()` **Прочитать для контекста:** 5. `TMP/mapping.csv` — полный результат 6. `TMP/договор-XXX001-03700_obfuscated.md` — обфусцированный файл 7. `TMP/примеры_договоров_для_ИИ/договор-XXX001-03700.docx` — оригинал (для сверки) **Не лезть:** `builder.py`, `extractor.py`, `replacer.py`, `session.py`, `templates/`, docs/, History/. ## Ключевые точки для проверки ### 1. `scanner.py` — `_next_token()` (стр. 63-82) ```python def _next_token(entity_type, counters): pool, prefix_key = TYPE_POOLS.get(entity_type, _FALLBACK_POOL) template = random.choice(pool) key = f"{prefix_key}_{template}" counters[key] = counters.get(key, 0) + 1 return f"{template}_{counters[key]:04d}" ``` Возвращает `Технология_0001`, `+7_000_000_0001`. **Никак не может вернуть** `АО «Прогресс»` или `+7 (495) 906-87-80`. ### 2. `scanner.py` — `scan_regex()` (стр. 89-108) ```python mapping[original] = _next_token(entity_type, counters) ``` Всегда вызывает `_next_token`. Результат должен быть кодом замены. ### 3. `scanner.py` — `scan_llm_ner()` (стр. 109-179) ```python mapping[val] = _next_token(ent_type, counters) ``` Тоже вызывает `_next_token`. Результат должен быть кодом замены. ### 4. `obfuscator.py` — порядок вызова (стр. 86-92) ```python scanner.scan_regex(text, self._mapping, self._counters) # сначала scanner.scan_llm_ner(all_texts, self._mapping, ...) # потом ``` ### 5. `config.py` — regex-паттерны: - `phone`: `(?:\+7|8)[\s\-]?\(?\d{3}\)?...` — должно матчить `+7 (495) 789-41-35` - `email`: `[a-zA-Z0-9._%+-]+@...` — должно матчить `info@nubes.ru` - `inn_ul`: `ИНН\s*\d{10}` — должно матчить `ИНН 9706005293` - `COMPANY_PATTERN`: `(?:ООО|ЗАО|...)\s+(?:«[^»]+»|"[^"]+"|...)` — должно матчить `ООО "НУБЕС"` и `ЗАО "XXX001"` - `PERSON_PATTERN`: `[А-Я][а-я]+\s+[А-Я]\.[А-Я]\.` — должно матчить `Новиков И.В.` ## Главный вопрос Каждый путь (regex и LLM) вызывает `_next_token()`. `_next_token()` физически не может выдать `АО «Прогресс»` или `+7 (495) 906-87-80`. Откуда в `mapping.csv` берутся реалистичные замены? Кто и где их генерирует В ОБХОД `_next_token()`?