docs(specs): drop type/status from folder names — header + Roadmap only

Folder names were NNN-T-S-NAME, so the status (S) letter forced a rename on
every status change — and refs to the full name went stale each time. One was
already broken in-tree (client.go pointed at 002-F-O-… while the folder was
002-F-C), and the submodule needed a cosmetic commit once already (010 O→C).

Make the number the only stable anchor:
- Rename all 12 folders NNN-T-S-NAME → NNN-NAME (git mv, history preserved).
- Type/status now live in a table header at the top of each SPEC.md (canon),
  aggregated by the Roadmap in SPECS/README.md (added missing 010, 012).
- Fix every ref to the old full name: README(.ru), docs/lx-changelog,
  docs/lx-config, intra-SPECS cross-links, PROBE.md git-apply path,
  TASKS.md titles, and transport/v2rayxhttp/client.go:5 (also un-stales O).
- Rewrite the convention + Workflow in SPECS/README.md and the DoD ritual in
  IMPLEMENTATION_PROMPT.md ("rename folder to …-C-…" → "set status in header
  + Roadmap").
- Bump submodule wireguard-go (0c0c10b): fix comments point at the new folder
  name SPECS/010-WG_ENDPOINT_GRO_SPLIT_BRAIN. Comment-only, no behavior change.

Not touched: gro-probe.patch (historical diagnostic diff artifact; §010 closed,
no longer applied).
This commit is contained in:
Leadaxe
2026-06-22 11:36:37 +03:00
parent 78fc9189e6
commit 09944c0103
57 changed files with 113 additions and 47 deletions
+2 -2
View File
@@ -42,7 +42,7 @@ In the sing-box ecosystem, forks that add XHTTP / AmneziaWG fall into two camps
| **AmneziaWG 2.0** | client endpoint | WireGuard obfuscation: `Jc/Jmin/Jmax`, `S1–S4`, `H1–H4` + **2.0**: `I1–I5` (CPS — decoy packets) | ✅ builds, passes `check`; dependency **activated** ([Leadaxe/wireguard-go-awg2-lx](https://github.com/Leadaxe/wireguard-go-awg2-lx) — sagernet base + obfuscation); **validated against a real AWG2 server**: handshake + keepalive + outbound traffic |
| **Masquerade `id/ip/ib`** | AWG sugar | WireSock-style declarative masquerade over `I1`: name a domain (`id`) + protocol (`ip`: `quic`/`dns`/`stun`/`sip`) + browser (`ib`) and the core builds the client-initiated `I1` decoy for you — `quic` = out-of-order fragmented Initial (i1+i2), `dns`/`stun`/`sip` = query/Binding-Request/INVITE | ✅ **`ip=quic` device-proven against a real LTE/WARP DPI** (~330 ms, eases Cloudflare WARP); `dns`/`stun`/`sip` build & pass `check` but are blocked as a protocol class to the WARP edge — for other providers |
Detailed reports: [`SPECS/002-…`](SPECS/002-F-C-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md), [`SPECS/003-…`](SPECS/003-F-C-AWG2_CLIENT_ENDPOINT/IMPLEMENTATION_REPORT.md) and [`SPECS/009-…`](SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES/IMPLEMENTATION_REPORT.md). Full config reference — **[docs/lx-config.md](docs/lx-config.md)**.
Detailed reports: [`SPECS/002-…`](SPECS/002-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md), [`SPECS/003-…`](SPECS/003-AWG2_CLIENT_ENDPOINT/IMPLEMENTATION_REPORT.md) and [`SPECS/009-…`](SPECS/009-WIRESOCK_MASQUERADE_PROFILES/IMPLEMENTATION_REPORT.md). Full config reference — **[docs/lx-config.md](docs/lx-config.md)**.
> **Not supported (Reality layer, deferred):** post-quantum Reality (`pqv` / ML-DSA-65) and Xray's `spiderX`. These are Xray-specific Reality features absent from sing-box, and Reality is the upstream TLS layer we keep untouched (it is not one of our features). Classic X25519 Reality works; a server that *mandates* post-quantum Reality won't connect. This is a sing-box limitation — best addressed upstream (we'd inherit it on rebase).
@@ -139,7 +139,7 @@ This is the **only profile device-proven against a real LTE/WARP DPI** (~330 ms)
`sip` are implemented as correct client-initiated requests but are blocked as a protocol class
toward the Cloudflare WARP edge (raw DNS/STUN/SIP to a datacenter IP is itself anomalous) —
they are kept for other providers whose DPI only checks packet well-formedness. See
[docs/lx-config.md](docs/lx-config.md) and [SPECS/009 examples](SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md).
[docs/lx-config.md](docs/lx-config.md) and [SPECS/009 examples](SPECS/009-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md).
---
+2 -2
View File
@@ -42,7 +42,7 @@
| **AmneziaWG 2.0** | клиентский endpoint | обфускация WireGuard: `Jc/Jmin/Jmax`, `S1–S4`, `H1–H4` + **2.0**: `I1–I5` (CPS — кастомные пакеты-приманки) | ✅ собирается, проходит `check`; зависимость **активирована** ([Leadaxe/wireguard-go-awg2-lx](https://github.com/Leadaxe/wireguard-go-awg2-lx) — sagernet-база + обфускация); **проверено живым AWG2-сервером**: handshake + keepalive + трафик наружу |
| **Маскировка `id/ip/ib`** | сахар над AWG | WireSock-стиль: декларативная маскировка поверх `I1` — домен (`id`) + протокол (`ip`: `quic`/`dns`/`stun`/`sip`) + браузер (`ib`), ядро строит клиент-инициированную `I1`-приманку: `quic` = out-of-order фрагментированный Initial (i1+i2), `dns`/`stun`/`sip` = query/Binding-Request/INVITE | ✅ **`ip=quic` device-проверен на реальном LTE/WARP DPI** (~330 мс, упрощает Cloudflare WARP); `dns`/`stun`/`sip` собираются и проходят `check`, но режутся как класс протокола к WARP-edge — для других провайдеров |
Подробные отчёты — в [`SPECS/002-…`](SPECS/002-F-C-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md), [`SPECS/003-…`](SPECS/003-F-C-AWG2_CLIENT_ENDPOINT/IMPLEMENTATION_REPORT.md) и [`SPECS/009-…`](SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES/IMPLEMENTATION_REPORT.md). Полный справочник конфига — **[docs/lx-config.md](docs/lx-config.md)**.
Подробные отчёты — в [`SPECS/002-…`](SPECS/002-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md), [`SPECS/003-…`](SPECS/003-AWG2_CLIENT_ENDPOINT/IMPLEMENTATION_REPORT.md) и [`SPECS/009-…`](SPECS/009-WIRESOCK_MASQUERADE_PROFILES/IMPLEMENTATION_REPORT.md). Полный справочник конфига — **[docs/lx-config.md](docs/lx-config.md)**.
> **Не поддерживается (слой Reality, отложено):** post-quantum Reality (`pqv` / ML-DSA-65) и `spiderX` из Xray. Это Xray-специфичные фичи Reality, которых нет в sing-box, а Reality — upstream-слой TLS, который мы держим нетронутым (это не одна из наших фич). Классический X25519 Reality работает; сервер, который **требует** post-quantum Reality, не подключится. Это ограничение sing-box — правильнее решать в upstream (получим на ребейзе).
@@ -138,7 +138,7 @@ QUIC-сессия. Это **единственный профиль, device-пр
`dns`/`stun`/`sip` реализованы как корректные клиент-инициированные запросы, но режутся как класс
протокола к WARP-edge (raw DNS/STUN/SIP к дата-центровому IP сам по себе аномален) — сохранены
для других провайдеров, чей DPI проверяет лишь корректность пакета. См.
[docs/lx-config.md](docs/lx-config.md) и [примеры SPECS/009](SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md).
[docs/lx-config.md](docs/lx-config.md) и [примеры SPECS/009](SPECS/009-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md).
---
@@ -1,5 +1,10 @@
# SPEC: 001 — FORK_BOOTSTRAP
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Заложить скелет downstream'а `sing-box-lx`: remotes, рабочая ветка, build-теги, версия с `-lx`, конвенция маркеров `// lx:` и шаблон гейтинга. После задачи репозиторий — корректный «upstream + ноль фич», готовый принимать XHTTP (002) и AWG2 (003).
---
@@ -1,4 +1,4 @@
# TASKS — 001-F-N-FORK_BOOTSTRAP
# TASKS — 001-FORK_BOOTSTRAP
## Git / GitHub
- [x] `origin` = Leadaxe/sing-box-lx, `upstream` = SagerNet/sing-box
@@ -1,5 +1,10 @@
# SPEC: 002 — XHTTP_CLIENT_TRANSPORT
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Добавить **клиентский XHTTP-транспорт** (совместимость с Xray XHTTP) для VLESS/VMess/Trojan, встроив его через **registry-рефактор** диспетчера v2ray-транспортов, за build-тегом `with_xhttp`.
---
@@ -1,4 +1,4 @@
# TASKS — 002-F-N-XHTTP_CLIENT_TRANSPORT
# TASKS — 002-XHTTP_CLIENT_TRANSPORT
## Registry-рефактор (касание upstream) — ✅ сделано, запушено
- [x] `transport/v2ray/registry.go`: `clientTransportRegistry`, `RegisterClient`, `lookupClientTransport`, `init()` встроенных типов (http/ws/quic/grpc/httpupgrade) — коммит `e111f800`
@@ -1,5 +1,10 @@
# SPEC: 003 — AWG2_CLIENT_ENDPOINT
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Добавить **клиентский AmneziaWG 2.0 endpoint** поверх существующего WireGuard-endpoint sing-box, используя `amneziawg-go` (как submodule + patches), за build-тегом `with_awg`.
---
@@ -1,4 +1,4 @@
# TASKS — 003-F-N-AWG2_CLIENT_ENDPOINT
# TASKS — 003-AWG2_CLIENT_ENDPOINT
## Зависимость
- [ ] Submodule `submodules/amneziawg-go` (pin коммит, совместимый с wireguard-go upstream)
@@ -1,5 +1,10 @@
# SPEC: 004 — BUILD_CI_RELEASE
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Собрать воспроизводимый конвейер сборки/CI/релизов `sing-box-lx`: кросс-платформенные бинари `sing-box` **и Android `libbox.aar`** с клиентским feature-set (полный upstream минус серверные/AI-теги) + lx-фичами (`with_xhttp`/`with_awg`), версия `-lx.N`, и **авто-ребейз на новый upstream-тег**.
---
@@ -1,4 +1,4 @@
# TASKS — 004-F-N-BUILD_CI_RELEASE
# TASKS — 004-BUILD_CI_RELEASE
## Сборка (desktop)
- [x] `Makefile.lx`: `lx-build` (output `sing-box`), `LX_TAGS`, `LX_LDFLAGS`, версия `-lx.N`
@@ -33,4 +33,4 @@
## Закрытие
- [x] DoD: зелёная CI-матрица (desktop ×6 + AAR) — релиз v1.13.13-lx.3
- [x] IMPLEMENTATION_REPORT.md
- [x] Папка → `C` (`004-F-C-BUILD_CI_RELEASE`)
- [x] Статус → `C` (шапка SPEC.md + Roadmap)
@@ -1,5 +1,10 @@
# SPEC: 005 — AWG2_RANGED_MAGIC_HEADERS
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Поддержать **диапазонные magic headers** AmneziaWG 2.0 (`H1`–`H4` вида `N-M`) в конфиге sing-box-lx. Только прослойка option → IpcSet; протокольный слой (vendored `Leadaxe/wireguard-go`) уже умеет диапазоны.
---
@@ -1,4 +1,4 @@
# TASKS — 005-F-C-AWG2_RANGED_MAGIC_HEADERS
# TASKS — 005-AWG2_RANGED_MAGIC_HEADERS
## Опции
- [x] `option/wireguard_awg.go`: тип `MagicHeader` (string-based, comparable) — UnmarshalJSON (number + `"N"`/`"N-M"`), MarshalJSON (number ↔ string), валидация uint32 / start ≤ end
@@ -20,5 +20,5 @@
## Документация и закрытие
- [x] `docs/lx-config.md`: `h1`–`h4` `int | "min-max"`, no-overlap, пример с диапазоном, маппинг awg.conf
- [x] `SPECS/README.md`: строка 005 в roadmap
- [x] IMPLEMENTATION_REPORT.md, DoD-чеклист, папка → `C`
- [x] IMPLEMENTATION_REPORT.md, DoD-чеклист, статус → `C` (шапка SPEC.md + Roadmap)
- [x] Тег `v1.13.13-lx.6` → `lx-release.yml` (desktop + AAR)
@@ -1,5 +1,10 @@
# SPEC: 006 — LINUX_MUSL_STATIC_ROUTER_BUILDS
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Публиковать **статические musl-бинари** `sing-box` под роутерные Linux-арки, **сохраняя NaïveProxy-outbound**. Закрывает [issue #1](https://github.com/Leadaxe/sing-box-lx/issues/1): нужен `linux-armv7`, и текущий `linux-arm64` не запускается на AsusWRT Merlin (`libdl.so.2: cannot open shared object file`).
---
@@ -1,4 +1,4 @@
# TASKS — 006-F-C-LINUX_MUSL_STATIC_ROUTER_BUILDS
# TASKS — 006-LINUX_MUSL_STATIC_ROUTER_BUILDS
## CI: musl-linux job
- [x] `lx-release.yml`: новый job `build_linux_musl`, матрица amd64/arm64/armv7(GOARM=7)/mipsle(GOMIPS=softfloat)
@@ -1,5 +1,10 @@
# SPEC: 007 — AWG_OVER_WIREGUARD_DETOUR_GUARD
| Поле | Значение |
|------|----------|
| Тип | B (bug) |
| Статус | C (complete) |
Отклонять (по образцу ядрового запрета «empty direct detour») конфигурацию, где
AmneziaWG-endpoint (источник с AWG-полями) имеет `detour` на **любой
WireGuard-based** endpoint — плоский WireGuard **или** AmneziaWG. По пакетам это
@@ -7,9 +12,9 @@ AWG-трафик, инкапсулированный внутри WireGuard-ту
**вешает ядро**. `detour` AWG-ноды на не-WireGuard outbound (VLESS, Trojan,
direct, …) — рабочий сценарий и остаётся разрешённым.
Тип: **Bug** в фиче [003 AWG2_CLIENT_ENDPOINT](../003-F-C-AWG2_CLIENT_ENDPOINT).
Баг **нашей** дельты (AWG-проводка + merged-форк wireguard-go), не upstream →
в скоупе по CONSTITUTION §3.1.
Баг в фиче [003 AWG2_CLIENT_ENDPOINT](../003-AWG2_CLIENT_ENDPOINT) **нашей**
дельты (AWG-проводка + merged-форк wireguard-go), не upstream → в скоупе по
CONSTITUTION §3.1.
---
@@ -135,7 +140,7 @@ device не поднимается, `started=false`, `return nil` (НЕ error
## 6. Ссылки
- Фича [003 AWG2_CLIENT_ENDPOINT](../003-F-C-AWG2_CLIENT_ENDPOINT)
- Фича [003 AWG2_CLIENT_ENDPOINT](../003-AWG2_CLIENT_ENDPOINT)
- LxBox §128 — образец поведения «вариант B» (ленивая detour-ошибка, ядро живёт):
`Leadaxe/LxBox/docs/spec/tasks/128-force-direct-out-detour.md`
- `submodules/wireguard-go/device/send.go` (junk-генерация в SendHandshakeInitiation)
@@ -32,4 +32,4 @@
- [x] IMPLEMENTATION_REPORT.md, SPEC, DoD
- [x] `SPECS/README.md` roadmap-строка 007
- [x] GH issue #2: комментарии со ссылками на коммиты + закрыт
- [x] Папка → `007-B-C-AWG_OVER_WIREGUARD_DETOUR_GUARD`
- [x] Статус → `C` (шапка SPEC.md + Roadmap)
@@ -9,7 +9,7 @@ endpoint'а** (`awgIpcLines` → `wireguard.NewEndpoint` → `check`/старт)
ошибкой, вместо рантайм-**паники** в горутине таймера ретрансмита handshake.
Баг **нашей** дельты (merged-форк wireguard-go + AWG-проводка), найден при разборе
[007](../007-B-C-AWG_OVER_WIREGUARD_DETOUR_GUARD) / [issue #2](https://github.com/Leadaxe/sing-box-lx/issues/2)
[007](../007-AWG_OVER_WIREGUARD_DETOUR_GUARD) / [issue #2](https://github.com/Leadaxe/sing-box-lx/issues/2)
→ в скоупе (CONSTITUTION §3.1).
## Диагноз
@@ -1,13 +1,18 @@
# SPEC: 008 — AWG_JUNK_PARAM_VALIDATION
| Поле | Значение |
|------|----------|
| Тип | B (bug) |
| Статус | C (complete) |
Отклонять невалидную junk-связку AmneziaWG (`jc`/`jmin`/`jmax`) **на уровне
конфига** (при построении endpoint, до handshake), а не падать рантайм-паникой в
горутине таймера. Главный мотив: при `jmin > jmax` вендоренный amneziawg-go
**паникует** (`rand.Int` с аргументом ≤ 0) — это краш ядра, а не управляемая
ошибка.
Тип: **Bug** в фиче [003 AWG2_CLIENT_ENDPOINT](../003-F-C-AWG2_CLIENT_ENDPOINT).
Найден при разборе [007](../007-B-C-AWG_OVER_WIREGUARD_DETOUR_GUARD) /
Баг в фиче [003 AWG2_CLIENT_ENDPOINT](../003-AWG2_CLIENT_ENDPOINT).
Найден при разборе [007](../007-AWG_OVER_WIREGUARD_DETOUR_GUARD) /
[issue #2](https://github.com/Leadaxe/sing-box-lx/issues/2). Баг **нашей** дельты
(merged-форк wireguard-go + наша AWG-проводка) → в скоупе (CONSTITUTION §3.1).
@@ -46,7 +51,7 @@ for i := 0; i < jc; i++ {
Невалидная junk-триада отвергается при построении endpoint'а с **понятной
ошибкой** (`./sing-box check` / старт фейлится управляемо), вместо рантайм-паники
позже. Это **fail-fast на уровне конфига** — в отличие от [007](../007-B-C-AWG_OVER_WIREGUARD_DETOUR_GUARD)
позже. Это **fail-fast на уровне конфига** — в отличие от [007](../007-AWG_OVER_WIREGUARD_DETOUR_GUARD)
(связка узлов, ловится лениво в dialer): здесь невалидно **одно** поле-сочетание
одного endpoint'а, видно сразу.
@@ -100,4 +105,4 @@ for i := 0; i < jc; i++ {
- `submodules/wireguard-go/device/send.go:143-154` (junk-цикл, паника)
- `submodules/wireguard-go/device/uapi.go:310-341` (uapi: только `>0`, связи нет)
- `transport/wireguard/device_awg.go` `awgIpcLines` (точка проверки)
- [007](../007-B-C-AWG_OVER_WIREGUARD_DETOUR_GUARD) / [issue #2](https://github.com/Leadaxe/sing-box-lx/issues/2) — где баг найден
- [007](../007-AWG_OVER_WIREGUARD_DETOUR_GUARD) / [issue #2](https://github.com/Leadaxe/sing-box-lx/issues/2) — где баг найден
@@ -1,12 +1,17 @@
# SPEC: 009 — WIRESOCK_MASQUERADE_PROFILES
| Поле | Значение |
|------|----------|
| Тип | F (feature) |
| Статус | C (complete) |
Декларативные поля маскировки **`Id` / `Ip` / `Ib`** (домен / протокол / браузер) —
из [WireSock Secure Connect](https://www.wiresock.net/) — которые **на уровне конфига
разворачиваются в AmneziaWG `I1` CPS-строку**. Вместо ручного `i1=<b 0x...>` пользователь
пишет осмысленные поля, а движок собирает пакет-приманку нужного протокола.
Тип: **Feature**, расширение [003 AWG2_CLIENT_ENDPOINT](../003-F-C-AWG2_CLIENT_ENDPOINT)
и [005 AWG2_RANGED_MAGIC_HEADERS](../005-F-C-AWG2_RANGED_MAGIC_HEADERS).
Расширение [003 AWG2_CLIENT_ENDPOINT](../003-AWG2_CLIENT_ENDPOINT)
и [005 AWG2_RANGED_MAGIC_HEADERS](../005-AWG2_RANGED_MAGIC_HEADERS).
Тег `with_awg`; новые файлы в зонах lx; сабмодуль не трогается.
---
@@ -1,4 +1,4 @@
# TASKS — 009-F-C-WIRESOCK_MASQUERADE_PROFILES
# TASKS — 009-WIRESOCK_MASQUERADE_PROFILES
## Решения
- [x] Механизм: **I1 CPS только** (S1–S4 невозможен против WARP; сабмодуль не трогаем)
@@ -45,7 +45,7 @@
- ✅ `go build ./...` без тегов — ок (xhttp отсутствует, upstream-эквивалент).
- ✅ `make -f Makefile.lx lx-build` — бинарь собран.
- ✅ `./sing-box check -c lx-test/config/xhttp_reality.json` (stream-one) и `xhttp_auto_reality.json` (auto) — pass.
- ⚠️ **Лайв против реального Xray reality+xhttp сервера** — НЕ выполнен (нет доступа к ноде). По решению владельца задача принята на синтетике (папка → **C**), лайв остаётся открытым TODO (см. «Дальше»). При первом доступе к ноде — прогнать и при расхождении переоткрыть.
- ⚠️ **Лайв против реального Xray reality+xhttp сервера** — НЕ выполнен (нет доступа к ноде). По решению владельца задача принята на синтетике (статус → **C**), лайв остаётся открытым TODO (см. «Дальше»). При первом доступе к ноде — прогнать и при расхождении переоткрыть.
## Ребейз-зона
@@ -79,7 +79,7 @@ case modePacketUp:
2. `requestURL` bare-path ветка + `dialStreamOne` голый путь (фикс 3.1 главный — проверяем stream-one лайв сразу).
3. auto-резолв + reality-детект helper (3.3, 3.4) + юнит-тест детекта.
4. Тест-конфиги, `sing-box check`, лайв-проверка (stream-one + auto на reality-ноде; packet-up регрессия).
5. DoD, IMPLEMENTATION_REPORT, статус папки → C.
5. DoD, IMPLEMENTATION_REPORT, статус (шапка SPEC.md + Roadmap) → C.
---
@@ -1,8 +1,13 @@
# SPEC: 011 — XHTTP_STREAM_ONE_DOWNLINK
| Поле | Значение |
|------|----------|
| Тип | B (bug) — баг в фиче 002 |
| Статус | C (complete) |
Починить XHTTP-режим **`stream-one`** (сломан с момента 002) и привести **`mode=auto`** к поведению Xray, чтобы конфиги `vless + reality + xhttp + mode:auto` поднимались на нашем ядре «как есть».
Тип: **B** (баг в фиче 002). Build-tag: `with_xhttp`. Scope: **client-only**.
Build-tag: `with_xhttp`. Scope: **client-only**.
---
@@ -18,7 +23,7 @@
- `sessionId == ""` → bidirectional **stream-one** ветка (один `httpServerConn`: `request.Body` = uplink, `ResponseWriter` = downlink);
- `sessionId != ""` → stream-up / packet-up.
Наш `dialStreamOne` ([transport/v2rayxhttp/conn.go:21](../../transport/v2rayxhttp/conn.go)) строит URL как `c.requestURL(sessionID)` → `<path>/<sessionId>`. Сервер парсит **непустой** sessionId, уходит в stream-down ветку (ждёт парный stream-up POST, которого нет), и в response.Body летят **не VLESS-байты**. VLESS-парсер читает первый байт как версию → `unknown version` (часто `0x58='X'` из HTTP-обвязки). Зафиксировано как «known bug» ещё в [002 IMPLEMENTATION_REPORT](../002-F-C-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md).
Наш `dialStreamOne` ([transport/v2rayxhttp/conn.go:21](../../transport/v2rayxhttp/conn.go)) строит URL как `c.requestURL(sessionID)` → `<path>/<sessionId>`. Сервер парсит **непустой** sessionId, уходит в stream-down ветку (ждёт парный stream-up POST, которого нет), и в response.Body летят **не VLESS-байты**. VLESS-парсер читает первый байт как версию → `unknown version` (часто `0x58='X'` из HTTP-обвязки). Зафиксировано как «known bug» ещё в [002 IMPLEMENTATION_REPORT](../002-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md).
### 1.2 `mode=auto` всегда → packet-up
@@ -82,4 +87,4 @@ Xray (`dialer.go`): `auto` → packet-up по умолчанию, **но есл
- [Xray-core splithttp dialer.go / client.go / hub.go](https://github.com/XTLS/Xray-core/tree/main/transport/internet/splithttp) — проводной контракт.
- [Xray issue #5635](https://github.com/XTLS/Xray-core/issues/5635) — «auto+reality → unexpected response version; stream-one работает».
- [XHTTP: Beyond REALITY (#4113)](https://github.com/XTLS/Xray-core/discussions/4113) — семантика auto.
- [002 SPEC / IMPLEMENTATION_REPORT](../002-F-C-XHTTP_CLIENT_TRANSPORT/) — исходная фича и зафиксированный stream-one bug.
- [002 SPEC / IMPLEMENTATION_REPORT](../002-XHTTP_CLIENT_TRANSPORT/) — исходная фича и зафиксированный stream-one bug.
@@ -1,4 +1,4 @@
# TASKS — 011-B-C-XHTTP_STREAM_ONE_DOWNLINK
# TASKS — 011-XHTTP_STREAM_ONE_DOWNLINK
## Подготовка
- [x] Ветка `lx-xhttp-streamone` от `lx` (имя `lx/xhttp` невозможно — ref `lx` уже лист)
@@ -33,6 +33,6 @@
## Закрытие
- [x] TASKS отражают факт (`[x]`)
- [x] IMPLEMENTATION_REPORT.md (корень бага, фикс, синтетика; лайв — honest caveat)
- [x] Обновить [002 IMPLEMENTATION_REPORT](../002-F-C-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md): stream-one fixed на синтетике (ссылка на 011)
- [x] Папка → `011-B-C-...` (принято на синтетике; лайв — открытый TODO в REPORT)
- [x] Обновить [002 IMPLEMENTATION_REPORT](../002-XHTTP_CLIENT_TRANSPORT/IMPLEMENTATION_REPORT.md): stream-one fixed на синтетике (ссылка на 011)
- [x] Статус → `C` (шапка SPEC.md + Roadmap; принято на синтетике, лайв — открытый TODO в REPORT)
- [ ] (опц.) Закрыть GH-issue по жалобе — комментарий со ссылкой на коммит (lx-память)
@@ -92,7 +92,7 @@ lx-trace download final: read=<N> write=<M> err=<...> timeout=<bool> ← о
1. Применить артефакт к чистому релизному дереву (`route/conn.go` + новый файл):
```
git apply SPECS/012-B-C-TCP_DOWNLINK_STALL_ZOMBIE_CONNS/instrumentation.patch
git apply SPECS/012-TCP_DOWNLINK_STALL_ZOMBIE_CONNS/instrumentation.patch
# либо вручную: diff для conn.go + создать route/conn_trace_lx.go из хвоста патча
```
(на момент написания зонд уже лежит в рабочем дереве: `M route/conn.go`,
@@ -5,7 +5,7 @@
| Тип | B (bug) — расследование |
| Статус | **C (closed) — НЕ удалось воспроизвести на lx.14.** Симптом наблюдался на РАЗНЫХ нодах, включая WG → это зонтик над «↓0»-сталлом, не один баг. WG-долю закрыл фикс **§010 GRO** (вошёл в lx.14, доказан). Для не-WG нод (VLESS/reality) §010 не применим, отдельного код-фикса нет — там симптом сейчас не воспроизводится без подтверждённого объяснения. См. раздел «Закрытие 22.06» ниже. |
| Зона | ядро `sing-box-lx` — `route/conn.go` (`connectionCopy`, общий relay); фикс WG-доли — submodule `wireguard-go` (GRO, §010, UDP/WG-only) |
| Связь | WG-доля симптома = [010-WG_ENDPOINT_GRO_SPLIT_BRAIN](../010-B-C-WG_ENDPOINT_GRO_SPLIT_BRAIN/SPEC.md) (closed, фикс в lx.14). §010 это UDP/WG-only → НЕ объясняет не-WG (VLESS) случаи; «виснет и на VLESS» строго не подтверждено (см. «Закрытие») |
| Связь | WG-доля симптома = [010-WG_ENDPOINT_GRO_SPLIT_BRAIN](../010-WG_ENDPOINT_GRO_SPLIT_BRAIN/SPEC.md) (closed, фикс в lx.14). §010 это UDP/WG-only → НЕ объясняет не-WG (VLESS) случаи; «виснет и на VLESS» строго не подтверждено (см. «Закрытие») |
| Артефакты | [PROBE.md](PROBE.md) — зонд (env-гейт `LX_CONN_TRACE`, не прогнан в боевом режиме); [instrumentation.patch](instrumentation.patch) — диф зонда; [RUN-PLAN.md](RUN-PLAN.md) — процедура прогона (на случай повторного появления) |
---
+1 -1
View File
@@ -22,7 +22,7 @@
4. `./sing-box check -c <тест-конфиг>` принимает конфиг с новой фичей (xhttp-транспорт / awg-endpoint).
5. Все правки upstream-файлов обёрнуты `// lx:begin <feat>` / `// lx:end <feat>` и лежат в отдельных коммитах.
6. **TASKS.md** отражает факт (`[x]`), заполнен **IMPLEMENTATION_REPORT.md**.
7. Папка задачи переименована в статус **C** при приёмке.
7. Статус задачи (шапка SPEC.md + Roadmap в SPECS/README.md) выставлен в **C** при приёмке.
---
+23 -7
View File
@@ -1,16 +1,30 @@
# SPECS — sing-box-lx (Spec Kit)
Все задачи — папки `NNN-T-S-NAME`. Внутри: SPEC.md → PLAN.md → TASKS.md → IMPLEMENTATION_REPORT.md.
Все задачи — папки `NNN-NAME`. Внутри: SPEC.md → PLAN.md → TASKS.md → IMPLEMENTATION_REPORT.md.
## Имя папки: `NNN-T-S-NAME`
## Имя папки: `NNN-NAME`
| Часть | Значение | Расшифровка |
|-------|----------|-------------|
| **NNN** | 001, 002, … | Сквозной номер |
| **T** (тип) | F / B / Q | Feature / Bug / Question (исследование) |
| **S** (статус) | N / O / W / C | New / Open (в работе) / Wait / Complete |
| **NNN** | 001, 002, … | Сквозной номер — **стабильный якорь**, не меняется никогда |
| **NAME** | UPPER_SNAKE | Название |
Имя папки **не несёт** тип/статус: они меняются по ходу задачи, а имя должно
оставаться стабильным (на него ссылаются из кода, доков и сабмодуля). Ссылки
давай короткой формой `SPECS/NNN-NAME` — она переживёт смену статуса.
## Тип и статус — в шапке SPEC.md + Roadmap
Источник правды по типу/статусу — **таблица-шапка в начале `SPEC.md`** каждой
задачи; [Roadmap](#roadmap-план-задач) ниже её агрегирует.
```markdown
| Поле | Значение |
|------|----------|
| Тип | F (feature) \| B (bug) \| Q (question/исследование) |
| Статус | N (new) \| O (open) \| W (wait) \| C (complete) |
```
## Файлы внутри папки
| Файл | Назначение |
@@ -33,10 +47,10 @@
## Workflow
1. Папка `SPECS/NNN-T-S-NAME/` (следующий номер, статус `N`).
1. Папка `SPECS/NNN-NAME/` (следующий номер). В шапке SPEC.md — `Тип` + `Статус: N`.
2. SPEC.md → PLAN.md → TASKS.md.
3. Реализация по TASKS с учётом IMPLEMENTATION_PROMPT и CONSTITUTION.
4. IMPLEMENTATION_REPORT.md, DoD-чеклист, переименование папки в `…-C-…`.
4. IMPLEMENTATION_REPORT.md, DoD-чеклист, статус в шапке SPEC.md и Roadmap → `C`.
## Roadmap (план задач)
@@ -51,6 +65,8 @@
| **007** | AWG_OVER_WIREGUARD_DETOUR_GUARD | **C** | ✅ **Код+тесты+DoD, Start-guard field-verified (Android lx.9).** Bug в 003: AWG-нода с `detour` на WireGuard-туннель (плоский WG или AWG) вешает ядро на Android (AWG внутри WG). **Два дополняющих guard'а:** Start-guard (`Endpoint.Start`, статическая транзитивная detour-цепь — device не поднимается) + selector-guard (`SelectOutbound` — при переключении селектора на WG гасит AWG-потребителей **до** переключения, через `ConsumersOf`). Оба — **вариант B** (ядро живёт, узел не встаёт, ошибка в лог). Ленивый dialer-guard (lx.8) откачен. detour на VLESS и WG→AWG — разрешены. Чинит [#2](https://github.com/Leadaxe/sing-box-lx/issues/2) |
| **008** | AWG_JUNK_PARAM_VALIDATION | **C** | ✅ **Код+тесты+DoD**. Bug в 003 (найден при 007): `jmin > jmax` паникует `rand.Int` в amneziawg-go (краш в timer-горутине). `validateJunk` в `awgIpcLines` отвергает на уровне конфига (`check`/старт), без паники. Узко — только краш-кейс; jc-несогласованность осознанно не трогаем (минимальный дифф, совместимость). Чинит [#3](https://github.com/Leadaxe/sing-box-lx/issues/3) |
| **009** | WIRESOCK_MASQUERADE_PROFILES | **C** | ✅ **Код+тесты+DoD; механизм проверен вживую (туннель + трафик на 009), релиз `v1.13.13-lx.11`.** WireSock-стиль `id`/`ip`/`ib` (домен/протокол/браузер) — декларативный сахар над `I1` CPS. Профили **quic** (1-RTT short header) / **dns** (EDNS OPT response) / **stun** (Binding Success Response) / **sip** (200 OK response), структуры портированы из open-source WireSock `amneziawg-proxy/src/transform.rs` (MIT). Механизм — **I1 only** (S1–S4 невозможен против WARP, сабмодуль не трогаем). `id` обязателен только для dns/sip (там идёт на провод), для quic/stun опционален. Строгая LDH-валидация домена (security-граница: инъекция в SIP/DNS). `ib` — без JA3-fingerprint (честно задокументировано). Все профили приняты реальным `newObfChain`; `sing-box check` зелёный; адверсариальный ревью (6 агентов) — 0 находок |
| **010** | WG_ENDPOINT_GRO_SPLIT_BRAIN | **C** | ✅ **Корень подтверждён на железе, фикс верифицирован** (download 0.44→20.7 Mbps), вмержен в `lx` (lx.14). Bug: WG-**endpoint** без `detour` на Android режет download (GRO split-brain — UDP_GRO включён, а receive-путь linux-only). Фикс — гейт `UDP_GRO` за `!android` в сабмодуле `wireguard-go` (`conn/`). UDP/WG-only |
| **011** | XHTTP_STREAM_ONE_DOWNLINK | **C** | ⚠️ **Принято на синтетике; лайв НЕ прогонялся** (нет reality+xhttp ноды). Bug в 002 (жалоба): `vless+reality+xhttp+mode:auto` не работал. Корень (сверено с Xray + [issue #5635](https://github.com/XTLS/Xray-core/issues/5635) + hiddify): stream-one слал `<path>/<sessionId>`, а Xray-сервер роутит stream-one только при пустом sessionId → downlink не-VLESS → `unknown version`. Фикс: голый путь без sessionId; `mode:auto`+reality → stream-one (детект reality по имени типа, без with_utls-зависимости). Юнит-тесты (URL-layout + reality-детект), `check`, сборки зелёные. Ветка `lx-xhttp-streamone`, **в `lx` не влито**; лайв — открытый TODO в REPORT |
| **012** | TCP_DOWNLINK_STALL_ZOMBIE_CONNS | **C** | ⚠️ **НЕ воспроизводится на lx.14** (статус закрытия — «not reproducible»). Симптом (↑517 ↓0, WhatsApp/Telegram «висят») наблюдался на РАЗНЫХ нодах, включая WG → зонтик над «↓0»-сталлом, не один баг. WG-долю закрыл [010](010-WG_ENDPOINT_GRO_SPLIT_BRAIN/SPEC.md) (UDP/WG-only). Для не-WG (VLESS/reality) отдельного код-фикса нет — симптом сейчас не воспроизводится без подтверждённого объяснения. Артефакты: зонд `LX_CONN_TRACE` (не прогнан в бою), [PROBE.md](012-TCP_DOWNLINK_STALL_ZOMBIE_CONNS/PROBE.md) |
> **Вне этого репозитория:** потребление ядра лаунчером (`singbox-launcher`) — парсинг `type=xhttp` в реальный XHTTP-транспорт (сейчас `023` маппит его в `httpupgrade`), AWG-поля в визарде, замена `bin/sing-box`. Это отдельные задачи в репозитории лаунчера.
+1 -1
View File
@@ -46,7 +46,7 @@ tracks only the fork. Versions are tagged `vX.Y.Z-lx.N`; releases are built by
so they are kept for other providers whose DPI only checks packet well-formedness.
* `id` is required for `quic`/`dns` (SNI / QNAME), optional for `sip` (pseudo-host
generated when absent) and `stun`.
* No submodule changes. See `SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES`.
* No submodule changes. See `SPECS/009-WIRESOCK_MASQUERADE_PROFILES`.
#### v1.13.13-lx.11
+1 -1
View File
@@ -176,7 +176,7 @@ DPI:
> `ip=stun` produces a hostname-less decoy regardless of `id`.
> - The motivating use case is easing connections to **Cloudflare WARP**.
**📖 [Detailed examples →](../SPECS/009-F-C-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md)** —
**📖 [Detailed examples →](../SPECS/009-WIRESOCK_MASQUERADE_PROFILES/EXAMPLES.md)** —
full per-profile configs (incl. a Cloudflare WARP one), the generated CPS for each,
a "which profile to pick" guide and a troubleshooting table of the exact validation
errors.
+1 -1
View File
@@ -2,7 +2,7 @@
// (a.k.a. "splithttp") v2ray transport for sing-box-lx. It is a lean-native
// implementation written on sing-box/sing primitives and the in-tree
// v2rayhttp HTTP/2 conn helpers, rather than vendoring Xray internals.
// See SPECS/002-F-O-XHTTP_CLIENT_TRANSPORT.
// See SPECS/002-XHTTP_CLIENT_TRANSPORT.
//
// Wire protocol (mirrors Xray-core transport/internet/splithttp):
//