139 lines
5.7 KiB
Markdown
139 lines
5.7 KiB
Markdown
# Программа `shine_login_guard`
|
||
|
||
Документ описывает целевое поведение программы классификации логинов SHiNE.
|
||
|
||
Задача программы:
|
||
|
||
- по логину определить класс регистрации;
|
||
- вернуть результат в `return_data`;
|
||
- не хранить PDA и не вести собственное состояние.
|
||
|
||
## 1. Назначение
|
||
|
||
`shine_login_guard` — маленькая служебная программа, которую вызывает `shine_users` через CPI до регистрации пользователя.
|
||
|
||
Она отвечает только на вопрос:
|
||
|
||
- можно ли зарегистрировать логин автоматически;
|
||
- является ли логин premium;
|
||
- является ли логин trademark/company.
|
||
|
||
## 2. Program ID
|
||
|
||
Текущий program id:
|
||
|
||
- `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo`
|
||
|
||
## 3. Состояние
|
||
|
||
У программы нет PDA-состояний и persistent storage.
|
||
|
||
Она опирается на статически сгенерированные словари, встроенные в бинарник на этапе сборки.
|
||
|
||
## 4. Внешние артефакты
|
||
|
||
Словари хранятся в:
|
||
|
||
- `src/dictionaries/premium/**/*.txt`
|
||
- `src/dictionaries/trademarks/**/*.txt`
|
||
|
||
На этапе build:
|
||
|
||
- все `.txt` файлы рекурсивно собираются;
|
||
- слова нормализуются;
|
||
- дубль-слова детектятся и логируются как warning;
|
||
- итоговые массивы слов вшиваются в generated Rust file.
|
||
|
||
## 5. Нормализация словаря
|
||
|
||
Слово словаря считается валидным, если:
|
||
|
||
- не пустое;
|
||
- длина не больше `20`;
|
||
- содержит только ASCII-буквы и цифры;
|
||
- после `trim()` и `lowercase()` остаётся валидным.
|
||
|
||
Символ `_` в словарных словах не допускается.
|
||
|
||
## 6. Единственная инструкция
|
||
|
||
Инструкция:
|
||
|
||
- `classify_login(login: String)`
|
||
|
||
Аккаунты:
|
||
|
||
- signer
|
||
|
||
Signer здесь технический и нужен как согласованный интерфейс вызова; бизнес-смысл подписи отсутствует.
|
||
|
||
## 7. Выходные классы
|
||
|
||
Программа возвращает `u32` через `set_return_data`:
|
||
|
||
- `0` — `CLASS_FREE`
|
||
- `1` — `CLASS_PREMIUM`
|
||
- `2` — `CLASS_TRADEMARK`
|
||
|
||
## 8. Правила нормализации логина
|
||
|
||
Перед классификацией логин нормализуется:
|
||
|
||
- пустой логин запрещён;
|
||
- длина исходного логина не больше `20`;
|
||
- символ `_` удаляется;
|
||
- остальные символы обязаны быть ASCII alnum;
|
||
- буквы приводятся к нижнему регистру.
|
||
|
||
Если нормализация не удалась:
|
||
|
||
- логин считается `CLASS_PREMIUM`.
|
||
|
||
Это намеренно жёсткое поведение: сомнительный логин не должен автоматически попадать в free-класс.
|
||
|
||
## 9. Правила классификации
|
||
|
||
Алгоритм:
|
||
|
||
1. Нормализовать логин.
|
||
2. Попробовать разрезать его на `1..3` слов из словарей.
|
||
3. Если среди найденных частей есть trademark-слово, вернуть `CLASS_TRADEMARK`.
|
||
4. Если есть только premium-слова, вернуть `CLASS_PREMIUM`.
|
||
5. Если словарное совпадение не найдено и длина нормализованного логина `<= 7`, вернуть `CLASS_PREMIUM`.
|
||
6. Иначе вернуть `CLASS_FREE`.
|
||
|
||
## 10. Разбиение на слова
|
||
|
||
Максимум слов в логине:
|
||
|
||
- `3`
|
||
|
||
Алгоритм разбиения:
|
||
|
||
- DFS/backtracking по префиксам строки;
|
||
- на каждом шаге берётся префикс длиной `1..20`;
|
||
- если префикс найден в premium или trademark словаре, поиск продолжается на остатке строки;
|
||
- если найден хотя бы один путь с trademark-словом, итог = `CLASS_TRADEMARK`;
|
||
- если найден путь только с premium-словами, итог = `CLASS_PREMIUM`.
|
||
|
||
## 11. Инварианты
|
||
|
||
Должно быть сохранено при переписи:
|
||
|
||
- тот же способ нормализации логина;
|
||
- та же семантика классов `0/1/2`;
|
||
- тот же лимит `MAX_WORDS_PER_LOGIN = 3`;
|
||
- тот же fallback `len <= 7 => premium`, если словарь ничего не нашёл;
|
||
- тот же порядок приоритета `TRADEMARK > PREMIUM > FREE`.
|
||
|
||
## 12. Что не обязано сохраниться при переписи
|
||
|
||
Можно менять без изменения бизнес-логики:
|
||
|
||
- build pipeline словарей;
|
||
- структуру хранения слов внутри бинарника;
|
||
- способ поиска слов, если сохраняется тот же результат;
|
||
- техническую форму возврата, если внешний контракт для `shine_users` останется совместимым.
|
||
|
||
Но если меняется именно интерфейс `return_data` или классы, это уже требует обновления `shine_users` и документации.
|