115 lines
5.9 KiB
Markdown
115 lines
5.9 KiB
Markdown
# Запрос к 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()`?
|