Zapret | Дорожная карта
2.37K subscribers
28 photos
24 files
3.57K links
Дорожная карта обновлений.

Узнайте что я буду редактировать в Запрет для обхода блокировок Дискорда и Ютуба в первую очередь

И ужаснуться моим техническим непонятным запискам без контекста.
Download Telegram
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 runtime dpi

👤 Автор: loop-uh
📅 Дата: 13.04.2026 15:45:34
🔗 SHA: 111d0b3

📊 Статистика:
➕ Добавлено: 542 строк
➖ Удалено: 351 строк
📝 Всего изменений: 893

📁 Изменено файлов: 28

✏️ src/app_context.py
+2 -2

Удалилось:
from app_state.launch_runtime_service import LaunchRuntimeService

from app_state.launch_runtime_service import LaunchRuntimeService


Добавилось:
from winws_runtime.state import LaunchRuntimeService

from winws_runtime.state import LaunchRuntimeService


✏️ src/app_state/app_runtime_state.py
+1 -1

Удалилось:
- не подменять собой `MainWindowStateStore` и не дублировать `LaunchRuntimeService`.


Добавилось:
- не подменять собой `MainWindowStateStore` и не дублировать `winws_runtime.state.LaunchRuntimeSe...


✏️ src/blockcheck/strategy_scanner.py
+10 -15

Удалилось:
from utils.process_killer import kill_winws_force

kill_winws_force()

logger.debug("kill_winws_force fallback failed: %s", e)

from utils.process_killer import kill_winws_force

if not kill_winws_force():

errors.append("kill_winws_force returned False")

except Exception as e:

errors.append(f"kill_winws_force: {e}")

logger.debug("kill_winws_force failed: %s", e)

try:

... и еще 5 строк

Добавилось:
from winws_runtime.runtime.sync_shutdown import shutdown_runtime_sync

shutdown_runtime_sync(reason="blockcheck_kill_fallback", include_cleanup=True)

logger.debug("canonical runtime shutdown fallback failed: %s", e)

from winws_runtime.runtime.sync_shutdown import shutdown_runtime_sync

result = shutdown_runtime_sync(reason="blockcheck_pre_scan", include_cleanup=True)

if result.still_running:

errors.append("runtime still running after canonical shutdown")

errors.append(f"canonical_runtime_shutdown: {e}")

logger.debug("canonical runtime shutdown failed: %s", e)


✏️ src/filters/strategy_detail/zapret2/page.py
+18 -45

Удалилось:
self._process_monitor_connected = False  # Флаг подключения к process_monitor

# Подключаемся к process_monitor для отслеживания статуса DPI

self._connect_process_monitor()

fields={"active_preset_revision", "preset_content_revision", "preset_structure_revision", "mode_r...

def _on_ui_state_changed(self, _state: AppUiState, changed_fields: frozenset[str]) -> None:

# Убедимся, что мы подключены к process_monitor

if not self._process_monitor_connected:

self._connect_process_monitor()

def _connect_process_monitor(self):

"""Подключается к сигналу processStatusChanged от ProcessMonitorThread"""

... и еще 31 строк

Добавилось:
fields={

"active_preset_revision",

"preset_content_revision",

"preset_structure_revision",

"mode_revision",

"launch_running",

"launch_phase",

},

def _on_ui_state_changed(self, state: AppUiState, changed_fields: frozenset[str]) -> None:

if (

... и еще 8 строк

✏️ src/main/window.py
+1 -1

Удалилось:
from managers.process_monitor_manager import ProcessMonitorManager


Добавилось:
from winws_runtime.monitoring import ProcessMonitorManager


... и еще 23 файлов

... и еще 18 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 перевёл stop-перед-immediate-restart на более мягкий контракт: - Во время stop-фазы перед следующим запуском runner теперь может останавливаться без разрушительного удаления WinDivert-служб. - То есть stop-перед-start больше не делает “тяжёлую” service-cleanup прямо в момент переключения. - Вместо этого следующий start остаётся единственной штатной точкой pre-cleanup, то есть предзапусковой очистки. Это важно, потому что ваш новый лог как раз показал, что последовательность: остановить процесс -> агрессивно снести service state -> сразу стартовать новый режим ломает WinDivert сильнее, чем помогает. Правки сделал здесь: - src/winws_runtime/runners/runner_base.py - src/winws_runtime/runners/zapret1_runner.py - src/winws_runtime/runners/zapret2_runner.py - src/winws_runtime/runtime/sync_shutdown.py - src/winws_runtime/runtime/workers.py - src/winws_runtime/runtime/controller.py - src/winws_runtime/runtime/restart_flow.py

👤 Автор: loop-uh
📅 Дата: 13.04.2026 16:02:29
🔗 SHA: 01f5f9a

📊 Статистика:
➕ Добавлено: 600 строк
➖ Удалено: 299 строк
📝 Всего изменений: 899

📁 Изменено файлов: 21

✏️ src/app_state/app_runtime_state.py
+0 -12

Удалилось:
def sync_autostart_from_registry(self) -> bool:

return self.set_autostart(self.detect_autostart_enabled())

@staticmethod

def detect_autostart_enabled() -> bool:

try:

from autostart.autostart_exe import is_autostart_enabled

return bool(is_autostart_enabled())

except Exception:

return False


✏️ src/autostart/autostart_exe.py
+11 -54

Удалилось:
import subprocess

from typing import Any, Callable, Optional

from utils.subproc import get_system_exe

TASK_NAME = "ZapretGUI_AutoStart"

def _run_schtasks(args: list[str], *, check_output: bool = True) -> Any:

cmd = [get_system_exe("schtasks.exe")] + args

for encoding in ("utf-8", "cp866", "cp1251"):

try:

return subprocess.run(

cmd,

... и еще 37 строк

Добавилось:
from typing import Callable, Optional

from autostart.task_scheduler_api import (

CANONICAL_TASK_NAME,

is_canonical_autostart_enabled,

register_canonical_autostart_task,

)

ok = register_canonical_autostart_task(exe_path)

if not ok:

_log("Ошибка создания задачи автозапуска через Task Scheduler API", "❌ ERROR")

_log(f"Создана задача автозапуска: {CANONICAL_TASK_NAME}", "INFO")

... и еще 1 строк

✏️ src/autostart/autostart_remove.py
+8 -24

Удалилось:
from utils.subproc import get_system_exe, run_hidden

CANONICAL_TASK_NAME = "ZapretGUI_AutoStart"

schtasks = get_system_exe("schtasks.exe")

check = run_hidden(

[schtasks, "/Query", "/TN", CANONICAL_TASK_NAME],

capture_output=True,

text=True,

encoding="cp866",

errors="ignore",

)

... и еще 11 строк

Добавилось:
from autostart.task_scheduler_api import (

CANONICAL_TASK_NAME,

delete_canonical_autostart_task,

is_canonical_autostart_enabled,

)

if not is_canonical_autostart_enabled():

if delete_canonical_autostart_task():

log(f"Не удалось удалить задачу {CANONICAL_TASK_NAME}", "⚠ WARNING")


... и еще 18 файлов

... и еще 11 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит

📝 запрет2

👤 Автор: loop-uh
📅 Дата: 15.05.2026 15:29:02
🔗 SHA: fd1eb4b

📊 Статистика:
➕ Добавлено: 40 строк
➖ Удалено: 17 строк
📝 Всего изменений: 57

📁 Изменено файлов: 3

🆕 SMS.md
+38 -0

Добавилось:
---

date:

tags:

link:

aliases:

img:

---

## SMS

```embed

title: "Скрытые угрозы SMS: сотовый оператор знает слишком много"

... и еще 25 строк

✏️ Zapret/Дорожная карта.md
+1 -0

✏️ Zapret2/Zapret2.md
+1 -17

Удалилось:
**[[home|Zapret 2]]** — инструмент для обхода DPI (Deep Packet Inspection) под авторством [bol-va...

## <img src="https://i.imgur.com/qTfQ4cf.png" width="25px"> [[download|Установка на Windows]] | [...

## Чем Zapret2 лучше обычного Zapret (*winws, nfqws*)?

В старом Zapret все методы обхода блокировок зашиты прямо в код на языке C. Программа делает ровн...

В Zapret 2 архитектуру разделили на две части. Ядро на C осталось — оно отвечает за перехват и от...

На практике это меняет всё. Роскомнадзор обновил ТСПУ и старый трюк сломался — достаточно поправи...

Дополнительно наш GUI делает точно также с [[preset|пресетами]] - чтобы быстро обмениваться ими м...

По сути старый Zapret — это заводской инструмент, который делает только то, что в него заложили н...

## [[router|Установка на роутеры]] | [[android|Установка на Android]]


Добавилось:
**[[home|Zapret 2]]** — инструмент для тонкого управления сетевым трафиком. Его самый известный п...


🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/todo

📝 запрет2

👤 Автор: loop-uh
🔗 SHA: fd1eb4b

📊 Статистика: 3 files changed, 40 insertions(+), 17 deletions(-)

📁 Изменённые файлы:
🆕 SMS.md\n✏️ "Zapret/\320\224\320\276\321\200\320\276\320\266\320\275\320\260\321\217 \320\272\320\260\321\200\321\202\320\260.md"\n✏️ Zapret2/Zapret2.md\n
🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/todo

📝 запрет2

👤 Автор: loop-uh
📅 Дата: 15.05.2026 15:29:02
🔗 SHA: fd1eb4b

📊 Статистика:
➕ Добавлено: 40 строк
➖ Удалено: 17 строк
📝 Всего изменений: 57

📁 Изменено файлов: 3

🆕 SMS.md
+38 -0

Добавилось:
---

date:

tags:

link:

aliases:

img:

---

## SMS

```embed

title: "Скрытые угрозы SMS: сотовый оператор знает слишком много"

... и еще 25 строк

✏️ Zapret/Дорожная карта.md
+1 -0

✏️ Zapret2/Zapret2.md
+1 -17

Удалилось:
**[[home|Zapret 2]]** — инструмент для обхода DPI (Deep Packet Inspection) под авторством [bol-va...

## <img src="https://i.imgur.com/qTfQ4cf.png" width="25px"> [[download|Установка на Windows]] | [...

## Чем Zapret2 лучше обычного Zapret (*winws, nfqws*)?

В старом Zapret все методы обхода блокировок зашиты прямо в код на языке C. Программа делает ровн...

В Zapret 2 архитектуру разделили на две части. Ядро на C осталось — оно отвечает за перехват и от...

На практике это меняет всё. Роскомнадзор обновил ТСПУ и старый трюк сломался — достаточно поправи...

Дополнительно наш GUI делает точно также с [[preset|пресетами]] - чтобы быстро обмениваться ими м...

По сути старый Zapret — это заводской инструмент, который делает только то, что в него заложили н...

## [[router|Установка на роутеры]] | [[android|Установка на Android]]


Добавилось:
**[[home|Zapret 2]]** — инструмент для тонкого управления сетевым трафиком. Его самый известный п...


🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Refactor preset profile architecture cleanup

👤 Автор: loop-uh
📅 Дата: 09.05.2026 21:52:56
🔗 SHA: 1701853

📊 Статистика:
➕ Добавлено: 328 строк
➖ Удалено: 294 строк
📝 Всего изменений: 622

📁 Изменено файлов: 31

✏️ src/donater/subscription_manager.py
+15 -55

Удалилось:
from PyQt6.QtCore import QThread, QObject, pyqtSignal

from donater.subscription_ui_applier import SubscriptionUiApplier

self._ui_applier = SubscriptionUiApplier(app_instance)

"""Асинхронная инициализация и проверка подписки"""

class SubscriptionInitWorker(QObject):

finished = pyqtSignal(object, object, bool)  # donate_checker, activation_info, success

progress = pyqtSignal(str)

def run(self):

try:

self.progress.emit("Инициализация системы подписок...")

... и еще 35 строк

Добавилось:
from PyQt6.QtCore import QThread, QObject

from donater.subscription_ui import (

apply_subscription_info_to_ui,

apply_subscription_init_failed_to_ui,

apply_subscription_ready_to_ui,

)

from donater.subscription_worker import SubscriptionInitWorker

"""Асинхронно запускает первичную проверку подписки."""

"""Обрабатывает результат фоновой проверки подписки."""

apply_subscription_init_failed_to_ui(self.app)

... и еще 5 строк

🆕 src/donater/subscription_ui.py
+40 -0

Добавилось:
from __future__ import annotations

from typing import Any, Dict

from log.log import log

def apply_subscription_info_to_ui(

app,

sub_info: Dict[str, Any],

) -> None:

"""Применяет Premium-статус к состоянию окна и заголовку."""

is_premium = bool(sub_info.get("is_premium"))

days_remaining = sub_info.get("days_remaining")

... и еще 19 строк

🗑️ src/donater/subscription_ui_applier.py
+0 -49

Удалилось:
from __future__ import annotations

from typing import Any, Dict, Optional

from log.log import log

class SubscriptionUiApplier:

"""Применяет Premium-статус к главному окну."""

def __init__(self, app_instance):

self.app = app_instance

def apply_subscription_info(

self,

sub_info: Dict[str, Any],

... и еще 27 строк

🆕 src/donater/subscription_worker.py
+34 -0

Добавилось:
from __future__ import annotations

import traceback

from PyQt6.QtCore import QObject, pyqtSignal

from log.log import log

class SubscriptionInitWorker(QObject):

"""Фоновый worker для первичной проверки Premium-статуса."""

finished = pyqtSignal(object, object, bool)  # donate_checker, activation_info, success

progress = pyqtSignal(str)

def run(self) -> None:

try:

... и еще 13 строк

✏️ src/main/post_startup_checks.py
+2 -2

Удалилось:
window.log_startup_metric("StartupChecksFinished", f"{duration_ms}ms")

window.log_startup_metric("StartupChecksStarted", "startup_checks_worker")


Добавилось:
window.log_startup_metric("StartupPostInitChecksFinished", f"{duration_ms}ms")

window.log_startup_metric("StartupPostInitChecksStarted", "startup_checks_worker")


... и еще 26 файлов

... и еще 21 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 удаление

👤 Автор: loop-uh
📅 Дата: 09.05.2026 22:05:23
🔗 SHA: 92d08ae

📊 Статистика:
➕ Добавлено: 124 строк
➖ Удалено: 136 строк
📝 Всего изменений: 260

📁 Изменено файлов: 4

🗑️ docs/gui_architecture_contract.md
+0 -73

Удалилось:
# GUI Architecture Contract

Дата фиксации: 2026-04-10

Этот документ описывает не пожелания, а архитектурный контракт GUI, который надо поддерживать при...

## Direct preset flow

- `direct_zapret1` использует выбранный source preset как единственный источник истины.

- `direct_zapret2` использует выбранный source preset как единственный источник истины.

- Канонический путь выбора direct-пресета: `PresetSelectionService` -> `DirectFlowCoordinator` ->...

- Канонический корень пресетов: `presets/` рядом с программой.

- Пользовательские direct-пресеты лежат только в `presets/presets_v1` и `presets/presets_v2`.

- Встроенные direct-пресеты лежат только в `presets/presets_v1_builtin` и `presets/presets_v2_bui...

... и еще 47 строк

✏️ src/donater/subscription_ui.py
+4 -8

Удалилось:
"""Применяет Premium-статус к состоянию окна и заголовку."""

app.update_title_with_subscription_status(

is_premium,

app.theme_manager.current_theme,

days_remaining,

)

log(f"Обновлён заголовок подписки: premium={is_premium}", "DEBUG")

app.update_title_with_subscription_status(False, None, 0)


Добавилось:
"""Применяет Premium-статус к состоянию окна и верхней метке."""

app.update_subscription_title_badge(is_premium)

log(f"Обновлена Premium-метка: premium={is_premium}", "DEBUG")

app.update_subscription_title_badge(False, source="subscription_init_failed")


🆕 src/main/startup_contract.md
+46 -0

Добавилось:
# Контракт Запуска

Этот документ фиксирует текущий контракт запуска GUI после разгрузки первого старта.

## Основные Роли

`window_bootstrap_for(...)` создаёт `AppContext`, главное окно и регистрирует окно как активное.

`WindowStartupMixin` отвечает за жизненный цикл окна во время старта:

- показать окно как можно раньше;

- собрать основной UI после первого показа;

- создать стартовые объекты через `startup_bootstrap_for(...)`;

- запустить `StartupCoordinator`;

- отметить метрики `StartupInteractive`, `StartupCoreReady`, `StartupPostInit`.

... и еще 21 строк

✏️ src/ui/theme_subscription_manager.py
+74 -55

Удалилось:
"""

Менеджер для работы с темами и подписками.

Содержит всю логику обновления UI в зависимости от статуса подписки и текущей темы.

"""

from typing import Optional

from PyQt6.QtWidgets import QWidget

from config.build_info import APP_VERSION

Миксин-класс для управления темами и отображением статуса подписки.

Должен использоваться вместе с основным классом окна.

def update_title_with_subscription_status(self: QWidget, is_premium: bool = False,

... и еще 41 строк

Добавилось:
from PyQt6.QtCore import Qt

from PyQt6.QtWidgets import QLabel, QSizePolicy, QWidget

PREMIUM_TITLE_BADGE_TEXT = "Premium"

Миксин для отображения Premium-статуса в верхней панели окна.

Базовый системный заголовок окна ставит ZapretFluentWindow при создании.

Этот миксин не пересобирает заголовок целиком, а обновляет только отдельную

Premium-метку, чтобы основной текст окна не прыгал при получении подписки.

def update_subscription_title_badge(

self: QWidget,

is_premium: bool = False,

... и еще 53 строк
... и еще 0 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Update theme_subscription_manager.py

👤 Автор: loop-uh
📅 Дата: 09.05.2026 22:06:38
🔗 SHA: ac85df2

📊 Статистика:
➕ Добавлено: 8 строк
➖ Удалено: 5 строк
📝 Всего изменений: 13

📁 Изменено файлов: 1

✏️ src/ui/theme_subscription_manager.py
+8 -5

Удалилось:
badge = self._ensure_subscription_title_badge()

if badge is None:

log(f"Premium-метка не обновлена: titleBar недоступен (source: {source})", "WARNING")

return


Добавилось:
badge = getattr(self, "_subscription_title_badge", None)

if badge is None:

return

badge = self._ensure_subscription_title_badge()

if badge is None:

log(f"Premium-метка не обновлена: titleBar недоступен (source: {source})", "WARNING")

return


🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Add feature public APIs and DNS layer

👤 Автор: loop-uh
📅 Дата: 10.05.2026 11:31:03
🔗 SHA: 68161f4

📊 Статистика:
➕ Добавлено: 3033 строк
➖ Удалено: 1066 строк
📝 Всего изменений: 4099

📁 Изменено файлов: 98

🆕 src/app/ARCHITECTURE.md
+249 -0

Добавилось:
# Архитектурный контракт GUI

Дата фиксации: 2026-05-10

Этот документ фиксирует текущие границы проекта. Он нужен не для описания всех деталей,

а чтобы новые правки не возвращали старую схему, где главное окно знает обо всём.

## Главное окно

`MainWindow` — это UI-оболочка.

Разрешено:

- держать виджеты окна;

- держать `WindowUiSession`;

- держать контроллер уведомлений;

... и еще 165 строк

🆕 src/app/ARCHITECTURE_DEBT.md
+157 -0

Добавилось:
# Архитектурный долг

Дата фиксации: 2026-05-10

Это список оставшихся прямых связей. Он нужен, чтобы не забыть, где проект ещё не дошёл

до чистой схемы `UI -> feature.public -> feature internals`.

## Контрольные поиски

Эти команды нужны, чтобы запрещённые связи были видимыми, а не держались в памяти:

```bash

rg -n "from winws_runtime\.(runtime|flow|runners)\.|import winws_runtime\.(runtime|flow|runners)\...

rg -n "from donater\.(service|subscription_manager|worker|device_store|api|.*_service)\.|import d...

rg -n "window\.launch_controller|host\.launch_controller|getattr\([^\\n]*(window|host)[^\\n]*laun...

... и еще 105 строк

✏️ src/app_context.py
+2 -10

Удалилось:
from presets.file_store import PresetFileStore

from presets.ui_store import PresetUiStore

from presets.selection_service import PresetSelectionService

from core.runtime.preset_runtime_coordinator import PresetRuntimeCoordinator

preset_runtime_coordinator_factory: Callable[..., PresetRuntimeCoordinator]

from presets.file_store import PresetFileStore

from presets.ui_store import PresetUiStore

from presets.selection_service import PresetSelectionService

from core.runtime.preset_runtime_coordinator import PresetRuntimeCoordinator

preset_runtime_coordinator_factory=lambda *args, **kwargs: PresetRuntimeCoordinator(*args, **kwar...


Добавилось:
from presets.public import PresetFileStore, PresetSelectionService, PresetUiStore

from presets.public import PresetFileStore, PresetSelectionService, PresetUiStore


✏️ src/blockcheck/strategy_scan_page_controller.py
+7 -4

Удалилось:
manifest = app_context.preset_mode_coordinator.get_selected_source_manifest(ZAPRET2_MODE)

from presets.file_service import PresetFileService

PresetFileService.from_launch_method(

).save_source_text_by_file_name(selected_file_name, updated_text)


Добавилось:
from presets.public import get_selected_source_preset_manifest

manifest = get_selected_source_preset_manifest(ZAPRET2_MODE, app_context=app_context)

from presets.public import save_preset_source_by_file_name

save_preset_source_by_file_name(

selected_file_name,

updated_text,

)


... и еще 94 файлов

... и еще 88 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 окно больше не центр вселенной

👤 Автор: loop-uh
📅 Дата: 15.05.2026 15:08:49
🔗 SHA: e67792c

📊 Статистика:
➕ Добавлено: 20198 строк
➖ Удалено: 19407 строк
📝 Всего изменений: 39605

📁 Изменено файлов: 374

🗑️ docs/gui_controller_rename_plan.md
+0 -352

Удалилось:
# GUI Controller Rename Plan

Дата фиксации: 2026-04-11

Этот документ описывает не конечный архитектурный контракт, а безопасный план миграции для слоя `...

Обновление состояния: 2026-04-12

На дату обновления план остаётся актуальным по стратегии, но уже не полностью совпадает со старой...

- naming-first стратегия остаётся канонической;

- часть folder-move этапа уже фактически произошла;

- дальше нельзя опираться на старую картину `src/ui/pages/...` как на единственный живой UI-слой;

- план нужно читать как живой маршрут миграции, а не как замороженный список старых путей.

## Зачем нужен план

... и еще 224 строк

🗑️ docs/gui_fluent_cutover_plan.md
+0 -1206

Удалилось:
# GUI Fluent Cutover Plan

Дата фиксации: 2026-04-12

Этот документ описывает не абстрактные идеи, а целевой план полной замены текущего `main_window*`...

Документ нужен как передаваемый контекст для следующего ИИ или следующей сессии. Его задача:

- зафиксировать, что именно мы считаем проблемой;

- зафиксировать, что именно мы сохраняем;

- зафиксировать, что именно подлежит полному удалению;

- дать один непротиворечивый план cutover без fallback и без второго источника истины.

## 1. Зачем вообще нужен этот cutover

Проблема проекта не в том, что GUI "не на Fluent". Наоборот, проект уже глубоко использует `qflue...

... и еще 784 строк

🆕 src/about/__init__.py
+1 -0

Добавилось:
"""Функции и планы страниц About/Support."""


🆕 src/about/plans.py
+132 -0

Добавилось:
from __future__ import annotations

import os

import subprocess

import webbrowser

from dataclasses import dataclass

from log.log import log

@dataclass(slots=True)

class AboutActionResult:

ok: bool

message: str

... и еще 99 строк

✏️ src/app/ARCHITECTURE.md
+1053 -46

Удалилось:
- держать контроллер уведомлений;

- обращаться из UI к `launch_controller` напрямую;

window.app_context -> сервисы приложения и общие store-объекты

UI вызывает DPI runtime только через публичный вход:

import winws_runtime.public as runtime_commands

или:

from winws_runtime.public import start_dpi_async

Исключение на текущем этапе:

- startup-код может создавать runtime-контроллер;

- аварийное закрытие может использовать sync shutdown;

... и еще 36 строк

Добавилось:
Быстрая проверка границ:

```bash

python src/app/architecture_checks.py

```

## Итоговая карта владения

Целевая схема проекта:

```txt

AppRuntime

-> собирает ядро приложения: AppPaths, State, Feature-слои

Feature-слои

... и еще 804 строк

... и еще 369 файлов

... и еще 364 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Update README.md

👤 Автор: loop-uh
📅 Дата: 15.05.2026 15:27:13
🔗 SHA: 6b5c203

📊 Статистика:
➕ Добавлено: 1 строк
➖ Удалено: 1 строк
📝 Всего изменений: 2

📁 Изменено файлов: 1

✏️ docs/README.md
+1 -1

Удалилось:
### Документация доступна здесь https://publish.obsidian.md/zapret


Добавилось:
### Документация доступна здесь https://publish.obsidian.md/zapret/Privacy/Zapret2/Zapret2


🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 окно точно не центр вселенной

👤 Автор: loop-uh
📅 Дата: 17.05.2026 13:45:34
🔗 SHA: a237480

📊 Статистика:
➕ Добавлено: 9615 строк
➖ Удалено: 8331 строк
📝 Всего изменений: 17946

📁 Изменено файлов: 222

✏️ .gitignore
+1 -0

Добавилось:
/logs


🆕 settings/settings.json
+158 -0

Добавилось:
{

"version": 1,

"program": {

"dpi_autostart": true,

"gui_autostart_enabled": false,

"strategy_launch_method": "zapret2_mode",

"profile_ui_mode": "basic",

"selected_source_preset_file_name_winws1": "",

"selected_source_preset_file_name_winws2": "",

"auto_update_enabled": true,

... и еще 148 строк

✏️ src/app/ARCHITECTURE.md
+183 -1167

Удалилось:
Дата фиксации: 2026-05-10

Этот документ фиксирует текущие границы проекта. Он нужен не для описания всех деталей,

а чтобы новые правки не возвращали старую схему, где главное окно знает обо всём.

Быстрая проверка границ:

```bash

python src/app/architecture_checks.py

```

## Итоговая карта владения

Целевая схема проекта:

```txt

... и еще 920 строк

Добавилось:
Дата фиксации: 2026-05-15.

Этот документ описывает текущее состояние кода. Главное правило простое:

окно показывает интерфейс, но не собирает приложение и не является общим

контейнером сервисов.

## Запуск

Каноническая цепочка запуска:

```text

src/main/entry.py

-> создаёт QApplication

-> создаёт ApplicationController

... и еще 171 строк

🆕 src/app/STATE_OWNERSHIP.md
+139 -0

Добавилось:
# State ownership

Этот документ фиксирует владение состоянием после чистки слоёв окна.

Главное правило:

```text

feature state хранит данные feature;

MainWindowStateStore хранит только короткое состояние, нужное общему UI.

```

`MainWindowStateStore` живёт в:

```text

src/app/state_store.py

... и еще 93 строк

✏️ src/app/__init__.py
+2 -1

Удалилось:
from app.features import AppFeatures, DnsFeature, build_app_features


Добавилось:
from app.feature_assembly import build_app_features

from app.features import AppFeatures, DnsFeature


✏️ src/app/architecture_checks.py
+613 -3

Удалилось:
re.compile(r"\b(?:premium|dns|hosts|presets|preset_)\b", re.IGNORECASE),

re.compile(r"\b(?:app_runtime\.features|features\.|get_premium_state|subscription_manager)\b"),

r"(?:app_context|ui_state_store|app_runtime_state|launch_controller|"


Добавилось:
def check_no_app_runtime_context(files: list[Path]) -> list[Problem]:

return _scan_lines(

files,

re.compile(r"\b(?:app_runtime|AppRuntime|window\.app_runtime|page\.window\(\)\.app_runtime)\.cont...

"AppRuntime.context нельзя добавлять как новый общий app_context",

)

def check_app_features_is_registry_only() -> list[Problem]:

path = SRC_ROOT / "app" / "features.py"

if not path.exists():

return [Problem(path, 1, "app/features.py не найден")]

... и еще 537 строк

... и еще 216 файлов

... и еще 212 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 234

👤 Автор: loop-uh
📅 Дата: 17.05.2026 13:50:17
🔗 SHA: 2855353

📊 Статистика:
➕ Добавлено: 3 строк
➖ Удалено: 158 строк
📝 Всего изменений: 161

📁 Изменено файлов: 2

✏️ .gitignore
+3 -0

Добавилось:
# Runtime user state

/settings/


🗑️ settings/settings.json
+0 -158

Удалилось:
{

"version": 1,

"program": {

"dpi_autostart": true,

"gui_autostart_enabled": false,

"strategy_launch_method": "zapret2_mode",

"profile_ui_mode": "basic",

"selected_source_preset_file_name_winws1": "",

"selected_source_preset_file_name_winws2": "",

"auto_update_enabled": true,

... и еще 148 строк

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Merge pull request #473 from youtubediscord/codex/remove-template-origin-preset-legacy

👤 Автор: loop-uh
📅 Дата: 17.05.2026 13:50:39
🔗 SHA: 6b0bf34

📊 Статистика:
➕ Добавлено: 34930 строк
➖ Удалено: 32732 строк
📝 Всего изменений: 67662

📁 Изменено файлов: 769

✏️ .gitignore
+4 -0

Добавилось:
# Runtime user state

/settings/

/logs


🗑️ docs/gui_architecture_contract.md
+0 -73

Удалилось:
# GUI Architecture Contract

Дата фиксации: 2026-04-10

Этот документ описывает не пожелания, а архитектурный контракт GUI, который надо поддерживать при...

## Direct preset flow

- `direct_zapret1` использует выбранный source preset как единственный источник истины.

- `direct_zapret2` использует выбранный source preset как единственный источник истины.

- Канонический путь выбора direct-пресета: `PresetSelectionService` -> `DirectFlowCoordinator` ->...

- Канонический корень пресетов: `presets/` рядом с программой.

- Пользовательские direct-пресеты лежат только в `presets/presets_v1` и `presets/presets_v2`.

- Встроенные direct-пресеты лежат только в `presets/presets_v1_builtin` и `presets/presets_v2_bui...

... и еще 47 строк

🗑️ docs/gui_controller_rename_plan.md
+0 -352

Удалилось:
# GUI Controller Rename Plan

Дата фиксации: 2026-04-11

Этот документ описывает не конечный архитектурный контракт, а безопасный план миграции для слоя `...

Обновление состояния: 2026-04-12

На дату обновления план остаётся актуальным по стратегии, но уже не полностью совпадает со старой...

- naming-first стратегия остаётся канонической;

- часть folder-move этапа уже фактически произошла;

- дальше нельзя опираться на старую картину `src/ui/pages/...` как на единственный живой UI-слой;

- план нужно читать как живой маршрут миграции, а не как замороженный список старых путей.

## Зачем нужен план

... и еще 224 строк

🗑️ docs/gui_fluent_cutover_plan.md
+0 -1206

Удалилось:
# GUI Fluent Cutover Plan

Дата фиксации: 2026-04-12

Этот документ описывает не абстрактные идеи, а целевой план полной замены текущего `main_window*`...

Документ нужен как передаваемый контекст для следующего ИИ или следующей сессии. Его задача:

- зафиксировать, что именно мы считаем проблемой;

- зафиксировать, что именно мы сохраняем;

- зафиксировать, что именно подлежит полному удалению;

- дать один непротиворечивый план cutover без fallback и без второго источника истины.

## 1. Зачем вообще нужен этот cutover

Проблема проекта не в том, что GUI "не на Fluent". Наоборот, проект уже глубоко использует `qflue...

... и еще 784 строк

🆕 src/about/__init__.py
+1 -0

Добавилось:
"""Функции и планы страниц About/Support."""


🆕 src/about/plans.py
+132 -0

Добавилось:
from __future__ import annotations

import os

import subprocess

import webbrowser

from dataclasses import dataclass

from log.log import log

@dataclass(slots=True)

class AboutActionResult:

ok: bool

message: str

... и еще 99 строк

... и еще 763 файлов

... и еще 759 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Сделал. Ветка осталась `main`, чужие уже существовавшие изменения не трогал. Что изменил: - Добавил общий ограничитель строк: [src/ui/log_limits.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/ui/log_limits.py:7). - Поставил лимиты на поля логов: обычные логи, ошибки, вывод `winws`, диагностика, BlockCheck, Telegram Proxy, Orchestra. - Ограничил очередь логов Telegram Proxy: [proxy_logger.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/telegram_proxy/proxy_logger.py:81). - Ограничил очередь логов Orchestra до обработки интерфейсом: [page.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/orchestra/ui/page.py:414). - Добавил тесты: [test_ui_log_limits.py](/mnt/g/Privacy/zapretgui/public_zapretgui/tests/test_ui_log_limits.py:1). Проверил: - `PYTHONPATH=src python -m unittest discover -s tests` — 28 тестов прошли. - `PYTHONPATH=src python -m app.architecture_checks` — проверка архитектуры прошла. - `py_compile` по изменённым файлам — без ошибок. Теперь старые строки в логовых окнах будут автоматически выкидываться, а в памяти останется только последний ограниченный хвост.

👤 Автор: loop-uh
📅 Дата: 17.05.2026 14:35:03
🔗 SHA: b05e720

📊 Статистика:
➕ Добавлено: 857 строк
➖ Удалено: 152 строк
📝 Всего изменений: 1009

📁 Изменено файлов: 33

✏️ src/app/ARCHITECTURE.md
+5 -1

Удалилось:
-> ApplicationController создаёт AppRuntime


Добавилось:
-> ApplicationController создаёт AppRuntime

WindowPageActions создаётся только после `window_notifications_setup.py`.

Причина простая: действия страниц используют `window_notification_center.notify`,

а центр уведомлений появляется именно на этапе `window_notifications_setup.py`.


✏️ src/app/architecture_checks.py
+2 -1

Удалилось:
r"removed_placeholder_profiles|_OUT_RANGE_UNSIGNED_SIMPLE_RE)\b"


Добавилось:
r"removed_placeholder_profiles|_OUT_RANGE_UNSIGNED_SIMPLE_RE|"

r"sanitize_presets_before_launch|_ensure_lua_init_lines|strip_strategy_tags)\b"


✏️ src/blockcheck/ui/log_build.py
+2 -0

Добавилось:
from ui.log_limits import BLOCKCHECK_LOG_VIEW_MAX_LINES, apply_text_line_limit

apply_text_line_limit(log_edit, BLOCKCHECK_LOG_VIEW_MAX_LINES)


✏️ src/blockcheck/ui/strategy_scan_page_build.py
+2 -0

Добавилось:
from ui.log_limits import BLOCKCHECK_LOG_VIEW_MAX_LINES, apply_text_line_limit

apply_text_line_limit(log_edit, BLOCKCHECK_LOG_VIEW_MAX_LINES)


✏️ src/diagnostics/ui/build.py
+2 -0

Добавилось:
from ui.log_limits import DIAGNOSTICS_LOG_VIEW_MAX_LINES, apply_text_line_limit

apply_text_line_limit(result_text, DIAGNOSTICS_LOG_VIEW_MAX_LINES)


✏️ src/log/log.py
+2 -0

Добавилось:
from ui.log_limits import MAIN_LOG_VIEW_MAX_LINES, apply_text_line_limit

apply_text_line_limit(self.log_text, MAIN_LOG_VIEW_MAX_LINES)


✏️ src/log/ui/logs_build.py
+9 -0

Добавилось:
from ui.log_limits import (

ERROR_LOG_VIEW_MAX_LINES,

MAIN_LOG_VIEW_MAX_LINES,

WINWS_OUTPUT_MAX_LINES,

apply_text_line_limit,

)

apply_text_line_limit(log_text, MAIN_LOG_VIEW_MAX_LINES)

apply_text_line_limit(errors_text, ERROR_LOG_VIEW_MAX_LINES)

apply_text_line_limit(winws_text, WINWS_OUTPUT_MAX_LINES)


... и еще 26 файлов

... и еще 23 файлов

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Причина: post-startup слой после запуска вызывает DNS-задачу через: application_post_startup.py (line 20) python features.dns.apply_dns_on_startup_async Но в DnsFeature такого поля не было. Сам DNS-метод уже существовал в dns.public, просто фасад DNS его не отдавал наружу. Поэтому exe падал с: text AttributeError: 'DnsFeature' object has no attribute 'apply_dns_on_startup_async' Исправил в dns.py (line 8): добавил apply_dns_on_startup_async в DnsFeature и связал его с dns_public.apply_dns_on_startup_async.

👤 Автор: loop-uh
📅 Дата: 17.05.2026 14:40:51
🔗 SHA: dc35db1

📊 Статистика:
➕ Добавлено: 9 строк
➖ Удалено: 0 строк
📝 Всего изменений: 9

📁 Изменено файлов: 2

✏️ src/app/feature_facades/dns.py
+2 -0

Добавилось:
apply_dns_on_startup_async: Callable

apply_dns_on_startup_async=dns_public.apply_dns_on_startup_async,


✏️ tests/test_main_startup_contract.py
+7 -0

Добавилось:
def test_dns_feature_exposes_startup_dns_entrypoint(self) -> None:

from app.feature_facades.dns import build_dns_feature

dns_feature = build_dns_feature()

self.assertTrue(callable(dns_feature.apply_dns_on_startup_async))


🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Причина: post-startup слой после запуска вызывает DNS-задачу через: application_post_startup.py (line 20) python features.dns.apply_dns_on_startup_async Но в DnsFeature такого поля не было. Сам DNS-метод уже существовал в dns.public, просто фасад DNS его не отдавал наружу. Поэтому exe падал с: text AttributeError: 'DnsFeature' object has no attribute 'apply_dns_on_startup_async' Исправил в dns.py (line 8): добавил apply_dns_on_startup_async в DnsFeature и связал его с dns_public.apply_dns_on_startup_async.

👤 Автор: loop-uh
🔗 SHA: dc35db1

📊 Статистика: 2 files changed, 9 insertions(+)

📁 Изменённые файлы:
✏️ src/app/feature_facades/dns.py
✏️ tests/test_main_startup_contract.py

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 В profile_setup_page.py (line 44) теперь главное место экрана — большой список готовых стратегий. Выпадающий список убран. Большие блоки “выбранная стратегия” и “что записано в профиль” убраны с главного экрана. Как теперь устроено: в главном окне profile сверху только компактные настройки; ниже вкладка Готовые стратегии с большим списком; активная стратегия выделяется строкой как в “Мои пресеты”: мягкая акцентная подложка + маркер слева; при наведении строка подсвечивается; жирного текста нет; границ между строками нет; строки компактные, высота 34px; при клике по уже активной стратегии открывается её подстраница; внутри подстраницы стратегии есть “Оценка стратегии”; “Что записано в профиль” и аргументы стратегии теперь живут на подстранице стратегии, а не в главном окне.

👤 Автор: loop-uh
🔗 SHA: 4921bc0

📊 Статистика: 10 files changed, 560 insertions(+), 50 deletions(-)

📁 Изменённые файлы:
✏️ src/main/window_notifications_setup.py
✏️ src/main/window_page_actions.py
✏️ src/main/window_startup.py
✏️ src/main/window_startup_setup.py
✏️ src/presets/builtin/winws2/Default v1 (game filter).txt
✏️ src/profile/service.py
✏️ src/profile/state.py
✏️ src/profile/ui/profile_setup_page.py
✏️ src/ui/widgets/win11_controls.py
✏️ tests/test_main_startup_contract.py

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 профиль

👤 Автор: loop-uh
🔗 SHA: 90d0260

📊 Статистика: 15 files changed, 635 insertions(+), 557 deletions(-)

📁 Изменённые файлы:
✏️ src/app/feature_facades/profile.py
✏️ src/profile/commands.py
✏️ src/profile/models.py
✏️ src/profile/service.py
✏️ src/profile/state.py
🗑️ src/profile/templates/all_profiles.txt
✏️ src/profile/ui/preset_setup_page.py
🆕 src/profile/ui/profile_display_items.py
✏️ src/profile/ui/profile_item.py
✏️ src/profile/ui/profiles_list.py
🆕 tests/test_build_resource_layout.py
🆕 tests/test_profile_display_items.py
🆕 tests/test_profile_filter_kind_switch.py
🆕 tests/test_profile_list_payload.py
🆕 tests/test_profile_strategy_resolution.py

🔗 Открыть на GitHub
💥 ВСЕ НАШИ ССЫЛКИ: https://t.me/runetvpnyoutubediscord

🔔 Новый коммит в youtubediscord/zapret

📝 Сделал большую проверку и поправил основное. Причина “всё выключено” была не одна: в живой установке выбран preset , там реально есть только 2 общих profile, а YouTube/Discord строки идут из каталога возможных profile и поэтому показывались выключенными. Плюс эти реальные profile попадали в группу «Прочее» внизу, поэтому сверху казалось, что выключено вообще всё. Что поправил: - добавил верхнюю группу , туда теперь попадают реальные profile выбранного preset; - открытие страницы profile больше не строит весь список заново; - оценки готовых стратегий теперь читаются из одним проходом, а не сотни раз; - убрал лишнюю передачу , она нигде не использовалась; - добавил тесты на первый запуск: пустые настройки и битый выбранный preset оба выбирают настроенный default preset. Основные файлы: - [service.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/profile/service.py) - [strategy_state.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/profile/strategy_state.py) - [profile_display_items.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/profile/ui/profile_display_items.py) - [profiles_list.py](/mnt/g/Privacy/zapretgui/public_zapretgui/src/profile/ui/profiles_list.py) - [test_preset_selection_defaults.py](/mnt/g/Privacy/zapretgui/public_zapretgui/tests/test_preset_selection_defaults.py) Проверил: - теста прошли; - прошёл; - прошёл; - прошёл; - на живом сборка detail-данных для profile с стратегиями заняла примерно . В On branch main

👤 Автор: loop-uh
🔗 SHA: 1c62a68

📊 Статистика: 16 files changed, 613 insertions(+), 58 deletions(-)

📁 Изменённые файлы:
✏️ src/hosts/page_controller.py
✏️ src/main/startup_coordinator.py
🆕 src/profile/list_interpreter.py
✏️ src/profile/models.py
✏️ src/profile/service.py
✏️ src/profile/state.py
✏️ src/profile/strategy_state.py
✏️ src/profile/ui/profile_display_items.py
✏️ src/profile/ui/profiles_list.py
✏️ src/winws_runtime/runtime/autostart.py
🆕 tests/test_hosts_page_runtime.py
✏️ tests/test_main_startup_contract.py
🆕 tests/test_preset_selection_defaults.py
✏️ tests/test_profile_display_items.py
✏️ tests/test_profile_list_payload.py
🆕 tests/test_startup_autostart.py

🔗 Открыть на GitHub
🐳1