# 06 — Упрощение: срез accidental-сложности спеки и кода **What to build:** Один проход упрощения по готовым issue 01–02 и спеке: убрать поддержку второй версии Xray, избыточные защитные проверки вне принятой модели угроз («доверенные пользователи машины», единственный пользователь редактирует свои файлы сам) и церемонии, не нужные личному foreground-инструменту. Поведенческие контракты из раздела «Не трогать» сохраняются без изменений. **Blocked by:** 02 — Управляемый Xray: полный штатный путь. **Status:** done **Резолюция (2026-07-20):** реализовано и принято. Дельта: CLI 1123→976, shell.bash 116→91, тесты 1357→1236 строк; сьюты: 34 unittest OK + 8 shell PASS. Ревью: 1 MAJOR (scoped IPv6 в упрощённом валидаторе — починен с регрессионным тестом под Python 3.8), 1 NIT отклонён аргументированно. Non-gating замечания ревью приняты как риски модели угроз. **Сначала прочитать:** 1. Этот файл целиком, затем `/tmp/xray-simplify-Zeo5/06-simplify/sweep.md` — там точный line-level blast radius каждого пункта (секция 2 — срезы A/B, секция 3 — SIMP-N). Номера строк — ориентир, сверяй с фактическим кодом. 2. `docs/specs/2026-07-15-proxy-client-design.md` — исходная спека. 3. `proxy-client/.local/bin/proxy-client`, `proxy-client/.config/proxy-client/shell.bash`, `tests/test_proxy_client.py`, `tests/test_proxy_client_managed.py`. Команды проверки (обе обязательны): - `python3 -m unittest discover -s tests` — baseline до изменений: 38 тестов, OK, ~60 с; - `bash tests/test_proxy_launchers.sh` — baseline: 9 проверок PASS. После изменений тестов станет меньше (удаляются тесты срезанных фич); все оставшиеся зелёные, новые счётчики указать в отчёте. ## A. Срез dual-version: остаётся только Xray 26.3.27 - [x] `VERSION_LINE` принимает только `26.3.27`; параметр `version` убран из сигнатур `parse_vless`, `build_xray_config`, `safe_summary`, `warn_legacy` и их вызовов; `xray_version` остаётся воротами «поддержанная версия или отказ» и по-прежнему показывает фактическую версию в сводке. - [x] Ветка эмиссии `allowInsecure` для 25.12.8 и запрет `pcs`/`vcn` для 25.12.8 удалены. `parse_boolean_fields` (валидация точных `true`/`false`, требование согласованности обоих полей, предупреждение при истинном значении) сохраняется; `allowInsecure` никогда не попадает в JSON. - [x] Тестовая ось версий схлопнута: lifecycle-тест гоняет один прогон 26.3.27 (обе локации профиля — default и `-f` — сохраняются); `test_old_version_preserves_explicit_legacy_insecure` и все 25.12.8-строки табличных тестов удалены. ## B. Срез проверки владения сокетом через /proc/net/tcp - [x] `process_owns_listener`, `process_socket_inodes`, `decode_proc_address` и их вызовы (в `verify_managed_state` и readiness-цикле `command_start`) удалены. Сохраняются: сверка PID/идентичности процесса, сверка адрес/порт машинного конфига со state и `check_endpoint`-проверка доступности порта. - [x] `test_verified_child_must_own_configured_listener` удалён вместе с веткой `FAKE_XRAY_LISTEN_PORT` в фейковом xray; `test_substituted_machine_port_fails_closed...` сохраняется и зелёный. - [x] Диагностические сообщения, упоминающие проверку владения слушателем (в `verify_managed_state` и readiness-цикле `command_start`), обновлены: после среза они описывают фактические проверки (идентичность процесса, сверка адрес/порт, доступность порта), а не владение сокетом. ## C. Диета входной валидации (файлы пишет сам пользователь) - [x] `validate_address`: сначала `ipaddress.ip_address`, иначе минимальная проверка «непустое ASCII-имя без пробелов, схемы `://`, `@`, `/` и квадратных скобок». RFC-строгость по меткам DNS, лимит 253 и сопутствующие тесты удалены. Оборачивание IPv6 в `[]` при сборке URL сохраняется. - [x] `load_config`: сохраняется отказ на неизвестной секции/ключе и на отсутствии обязательного ключа (ловит реальные опечатки) и диапазон порта. Удалены: скан NUL, guard UTF-8-декодирования, отдельный запрет `[DEFAULT]`, запрет CR/многострочных значений, case-sensitive `optionxform`; соответствующие подкейсы тестов удалены. - [x] `read_profile`: сохраняются разрешение симлинка, проверка прав (group/other → ошибка с подсказкой `chmod 600`) и правило «ровно одна непустая строка». Удалены скан NUL и guard UTF-8. - [x] `parse_query`: сохраняются отказ на неизвестном и на повторном query-параметре. Удалены regex на сырые `%`-последовательности и посимвольный запрет управляющих символов. ## D. Диета церемоний - [x] `write_private_json`: простая запись файла с правами 0600 внутри уже-0700 каталога; O_EXCL/fsync/`os.replace`/PID-суффиксы удалены. - [x] Валидация `PROXY_PREFLIGHT_TIMEOUT` и `PROXY_CLIENT_STOP_TIMEOUT` — один guard «`float()` успешен и > 0, иначе понятная ошибка»; `math` не импортируется; тесты экстремальных значений (nan/inf/1e-7/1e308) удалены. Для `PROXY_PREFLIGHT_TIMEOUT` оставить один тест «плохое значение → понятный отказ»; для `PROXY_CLIENT_STOP_TIMEOUT` отдельного теста нет и добавлять его не нужно — достаточно guard'а. - [x] `check_reachable` использует `socket.create_connection(timeout=...)` без SIGALRM/setitimer-машинерии. Принятый риск (записан здесь): зависший DNS-резолв на external-пути не ограничен таймаутом — для личного инструмента пользователь прерывает вручную. - [x] `extra` и `alpn` разбираются один раз в `parse_vless`, результат сохраняется в профиле и переиспользуется в `build_xray_config` без повторного разбора. `parse_json_object` сохраняет оба отказа — на повторах ключей и на JSON-константах (`reject_constant` остаётся): существующий тест требует отказ на уровне разбора с диагностикой про `extra` и без запуска `run -test`, и это дешевле, чем переносить ответственность на сериализацию. - [x] `process_alive` — только `os.kill(pid, 0)`; чтение `/proc/PID/stat` ради zombie-состояния удалено. - [x] Отпечаток профиля (`profile_fingerprint`) удалён из state и кода: он не участвует ни в одном решении. Смена профиля по-прежнему блокируется существованием state. Вместе с ним обновлены `STATE_KEYS` и все тестовые фикстуры state (включая точную сверку набора ключей в managed-тестах): устаревший ключ в фикстуре не должен ронять сверку ключей раньше, чем тест дойдёт до проверяемой идентичности процесса. ## E. shell.bash: средняя форма приёма `env` - [x] `_proxy_apply_env_file`: при ненулевом коде возврата CLI окружение не меняется вовсе; успешный вывод разбирается построчно по первому `=`; применяются (через `printf -v`, без `eval`) только восемь известных ключей, прочие строки — ошибка без частичного экспорта. Удалены сканы NUL/CR, отдельный детектор повторов и проверка «ровно восемь строк». Свойство «нет частичного изменения окружения при ошибке» сохраняется и остаётся покрыто тестом. - [x] `tests/test_proxy_launchers.sh` приведён к средней форме: проверки повторов/CR/NUL/счётчика строк, соответствующие удалённой машинерии, убраны или переписаны; проверки «ненулевой код возврата CLI → окружение не тронуто», «неизвестная строка → ошибка без частичного экспорта» и владения функциями остаются зелёными. ## F. Спека и соседние issue приведены к новому объёму - [x] Из спеки удалены: ветка 25.12.8 (все места из секции 2 sweep-файла), флаги `-v`/`--debug` (не реализованы), упоминание отпечатка профиля в state; описания валидации/атомарности смягчены до фактического поведения после этого issue. Формулировка идентичности процессов («PID + время старта + исполняемый файл») в спеке не меняется. - [x] Issue 03: добавлен явный мандат «идентичность = PID + время старта (`/proc/PID/stat`) + исполняемый файл ребёнка / путь скрипта супервизора; текущий argv-обход заменить этим механизмом»; убраны унаследованные упоминания срезанных фич, если есть; строка Blocked by дополнена: «06 — Упрощение». - [x] Issue 05: приёмка сведена к одной версии Xray 26.3.27; упоминания 25.12.8 удалены. Пункты про РЕД ОС сохранены (решение пользователя 2026-07-20: целевые системы шире Ubuntu — РЕД ОС, возможно Astra Linux и Alt Linux; инструмент могут использовать коллеги). - [x] В спеке в раздел ручной проверки добавлены Astra Linux и Alt Linux как кандидаты «по мере доступности» с тем же правилом, что для РЕД ОС: недоступная среда явно записывается как неподтверждённая, поддержка не заявляется без фактической проверки версии Python и прогона. - [x] В issue 01 и 02 добавлена одна строка после Status: «Часть требований пересмотрена в 06 — см. 06-simplification-pass.md»; чекбоксы 01 и 02 не редактируются (issue 01 описывает строгую приёмку `env`, которую этот issue смягчает, — без пометки он противоречил бы коду). ## G. Не трогать (границы) - Строгий отказ на неизвестном/повторном query-параметре VLESS. - Точечный `stop` только по проверенному PID; никакого pkill. - Foreground-супервизор, проброс сигналов, очистка state. - Изоляция окружения `run` (proxy-переменные только у ребёнка), сохранение argv и кода возврата, `--`-разделитель. - Fail-fast `pclaude`/`pcodex`, обратная совместимость: без машинного конфига — внешний `hproxy.local:12334`. - Проверка прав файла профиля (chmod 600) и loopback-only вход. - Авто-диагностика внешнего IP на старте (несмертельная) — остаётся. - Секреты: полная VLESS-ссылка, UUID, ключи не появляются в stdout/stderr/ argv — все существующие тесты на это остаются зелёными. - `bash/.bash_functions`, установщик, README — не входят в этот issue. - Никаких коммитов. ## Отчёт исполнителя 1. Изменённые файлы со строкой «зачем» на каждый. 2. Команда тестов и счётчик (все зелёные, указать новое число). 3. Чекбоксы: закрыт / не закрыт и почему. 4. Итоговая дельта `wc -l` по CLI, shell.bash и обоим тест-файлам против baseline (1123 / 116 / 467 / 890). 5. Сомнения, если есть.