zapret-kvn/.agents/skills/zapret-kvn-json-routing/references/native-routing.md
loop-uh a326031692
Some checks failed
Windows project source guards / test (push) Failing after 58s
Удалён мёртвый код пресетов маршрутизации
Страница RoutingPage нигде не создавалась, а её пресеты сайтов и приложений
(service_presets, process_presets) читал только старый сборщик
build_xray_config, который в рабочем пути не участвует: маршрут задаёт
сырой JSON активного конфига. Пресет «Google → напрямую» при этом выглядел
как действующее правило и уводил разбор жалоб в сторону.

Поля service_routes и process_preset_routes убраны из RoutingSettings;
старый профиль читается как прежде, лишние ключи пропадают при сохранении.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:18:17 +03:00

7 KiB

Native Routing Contract

Ownership map

Layer Paths Authority
Shipped templates data/templates/sing-box/*.json, data/templates/xray/*.json Versioned defaults and reset/import sources
Active raw configs data/configs/sing-box/*.json, data/configs/xray/*.json Runtime routing and DNS source of truth
Runtime copies data/runtime/*.json or manager-owned temporary files Launch artifacts; do not author product policy here
Legacy GUI routing RoutingSettings, engines/xray/config_builder.py Separate tun2socks/legacy path, not raw sing-box/Xray modes

application/profile_service.py copies a selected or imported template into the corresponding active config. Reset performs the same copy. Saving in the raw editor writes the active config.

The self-updater preserves the installed data/ directory. To deliver template updates through that boundary, build.py generates assets/template-update from the versioned data/templates tree. Before the UI starts, template_sync.py compares each same-path active config with the previously installed template. A JSON-equivalent copy is replaced by the new template; otherwise each top-level section that still equals the previous template follows the new one (merge_stock_sections) and every user-edited section stays verbatim. No section, dns included, is rewritten outside this update merge. The generated asset is transport, not a second authoring source.

The «Маршрутизация» GUI (xray_fluent/ui/configs_page.py, xray_fluent/ui/singbox/) edits the same active JSON: forms are generated from the pinned core schema in assets/sing-box-schema/ and change the parsed document in place, preserving unknown keys, key order and the scalar/list form of Listable fields. It is an editor of native JSON, not a routing layer; the JSON page shows the identical document.

Mode map

Mode Routing owner App-owned runtime work
System proxy to sing-box Active sing-box JSON Replace source proxy/TUN inbounds with public SOCKS/HTTP inbounds; allocate ports
sing-box TUN Active sing-box JSON Remove proxy inbounds; assign fresh TUN interface name
System/manual proxy to Xray Active Xray JSON Allocate proxy/API ports and add metrics contract
Xray TUN Active Xray JSON Add/keep TUN inbound, strip proxy inbounds, bind outbounds to the physical interface when required
sing-box hybrid Xray sidecar Active sing-box JSON at the front Route only the proxy outbound through the generated sidecar; preserve sing-box direct decisions
tun2socks fallback GUI RoutingSettings and generated Xray config Outside raw JSON ownership

Native sing-box rules

Use route.rules and upstream field names such as:

  • process_name, process_path, process_path_regex;
  • domain, domain_suffix, domain_keyword, domain_regex;
  • ip_cidr, ip_is_private;
  • rule_set, protocol, inbound;
  • action and outbound.

Prefer the current explicit route action:

{
  "process_name": [
    "Example.exe",
    "example-helper.exe"
  ],
  "action": "route",
  "outbound": "direct"
}

Do not put Xray values such as domain:example.com, full:example.com, geosite:*, or geoip:* into a sing-box native rule. Use sing-box fields or native rule_set entries.

Keep this normal priority shape:

  1. non-final {"action": "sniff"};
  2. DNS handling such as {"protocol": "dns", "action": "hijack-dns"};
  3. narrow protected/direct process rules;
  4. LAN and other narrow rules;
  5. broader process/domain/rule-set rules;
  6. route.final for unmatched traffic.

Rules are evaluated in order. A final route action stops ordinary matching. Put a forced direct process rule before any broader proxy rule that can match the same traffic.

The runtime may insert narrowly scoped endpoint, metrics, or hybrid-protection rules ahead of source-authored policy. Those rules match app-owned inbounds or the selected proxy endpoint and must not become a second product-policy layer.

Ensure the referenced tag exists, normally:

{
  "type": "direct",
  "tag": "direct",
  "domain_resolver": "bootstrap-dns"
}

Native Xray rules

Use routing.rules with Xray field-rule keys such as:

  • type: "field";
  • process;
  • domain with Xray-native items such as domain:, full:, regexp:, or geosite: when supported by the bundled data/core;
  • ip with CIDR, geoip:, or other Xray-native values;
  • network, inboundTag, port;
  • outboundTag.

Example process rule:

{
  "type": "field",
  "process": [
    "Example.exe",
    "example-helper.exe"
  ],
  "network": "tcp,udp",
  "outboundTag": "direct"
}

Put project policy rules at the beginning of the template's routing.rules, before broad proxy rules. The runtime metrics rule may be inserted ahead of them for a dedicated metrics inbound; it does not match normal application traffic.

Ensure the referenced direct outbound exists, normally:

{
  "tag": "direct",
  "protocol": "freedom",
  "settings": {}
}

Reserved routing tags

  • Keep proxy as the selected-node placeholder when the template expects the application to replace it.
  • Keep direct for native direct egress.
  • Keep block for the engine's native block/blackhole outbound.
  • Do not rename app-owned tags beginning with __app_ without tracing every runtime consumer.

Files to trace before architecture changes

  • xray_fluent/application/profile_service.py: template, active-config, reset, and save ownership.
  • xray_fluent/application/template_sync.py: updater-safe delivery of shipped templates and preservation of user-edited active JSON.
  • xray_fluent/engines/singbox/runtime_planner.py: proxy/TUN inbound contracts, selected outbound, bootstrap rule, and hybrid sidecar.
  • xray_fluent/application/xray_runtime_service.py: raw Xray metrics, TUN, selected outbound, and loop-prevention contracts.
  • xray_fluent/ui/configs_page.py and ui/dashboard_page.py: user-facing mode semantics.
  • docs/sing-box/runtime-config.md: current raw-config model and route-order explanation.
  • docs/sing-box/reference/route-rules.md: local upstream-aligned sing-box field reference.
  • docs/template-editor-v1.md and docs/sing-box/template-format-v1.md: design context only; do not treat placeholders as implemented runtime behavior without source proof.
  • tests/test_yandex_music_direct_templates.py: concrete cross-core example that checks native process rules and first-match priority in every shipped template.

Verification checklist

  1. Parse every changed JSON file.
  2. Assert exact process/domain values, native action fields, and rule priority in a focused unit test.
  3. Run sing-box check for changed sing-box templates.
  4. Run xray run -test for changed Xray templates.
  5. Run the relevant Python suite and git diff --check.
  6. Test both automatic synchronization of untouched active configs and preservation of user-edited active configs.
  7. Do not claim build or installed-runtime verification unless each was actually performed.