Критерий границы — ADR-027 (2026-08-31). Раздел больше не перечисляет подсистемы по именам, а отвечает на вопрос «кто принимает решение»:
- Своё — там, где мы решаем, что считать правильным: раскладка бокса, момент инвалидации стиля, порядок отрисовки, поведение вложенного контекста просмотра, что браузер показывает пользователю и чего он не отправляет.
- Готовое — там, где решение уже принял комитет и записал в спеку: формат файла, таблица Unicode, OpenType-lookup, конечный автомат разбора URL, алгоритм сжатия, криптографический примитив.
Проверка: если мы напишем это сами и разойдёмся с эталонной реализацией — правы мы или нет? Если неправы по определению, решение принадлежит спеке. Требования trait-anchor и обоснования в теле коммита не отменяются — см. конец раздела.
Стратегия (обновлено 2026-05-15): сначала рабочий браузер, потом разговор «что переписывать самим». Раньше §5 формулировался бинарно — «всё своё, кроме 5 exception». На практике это упирало в задачи, которые ничего не определяют в идентичности Lumen, но стоят месяцев работы (image decoders, Unicode UAX-таблицы, Brotli, WOFF2, HTTP/3). Новая формулировка — две категории exception:
- Permanent. Никогда не пишем сами. Универсальное правило безопасности / здравого смысла. 5 шт.
- Provisional accelerators. Берём готовое сейчас ради скорости Phase 1-3, но за trait-anchor в
lumen-core::ext, чтобы при желании заменить. У каждого — «graduation criterion»: событие, при котором имеет смысл писать своё. Большинство criterion-ов в духе «реалистично — никогда» (формат стабильный, без архитектурной ценности для Lumen) — это не лицемерие, а честная маркировка.
«Не делаем Google Chrome» — это про ядро. Lumen остаётся проектом про собственный rendering engine. HTML/CSS/DOM/style/layout/paint/font/encoding, URL, HTTP/1.1, DNS-резолвер с DoH/DoT, adblock matcher, knowledge layer (§12), UI shell — всегда наши. Если кто-то предлагает «возьми готовое» для пункта из этого списка — это уже Chrome-форк, а не Lumen.
Поэтому мы по-прежнему пишем свой код для:
- HTML / CSS парсеров, DOM, style cascade, selectors;
- layout (block, inline, flex, grid), paint, compositing;
- Punycode (RFC 3492) и homograph-проверки IDN — часть решения «что показать в адресной строке», см.
lumen-core::idn. Сам разбор URL закрытLIB-6(2026-09-01): scheme/host/path/query/fragment splitting, percent-encoding, dot-segment removal иresolve()теперь конечный автомат WHATWG через крейтurl(см. Permanent exceptions ниже) — своя ~370-строчная реализация проходила 41.95%urltestdata.json(LIB-0), новая — 81.86%; - HTTP/1.1, HTTP/2, DNS-резолвера с DoH/DoT (HTTP/3 — через provisional
quinn); - определения и конвертации кодировок (cp1251, KOI8-R, CP866 и др.);
PNG-декодера (готов в— устарело, исправлено 2026-08-31. Своего PNG-декодера нет:lumen-image+ свой DEFLATE…)crates/engine/image/src/png/mod.rs— 125-строчная обёртка надzune_png, JPEG/WebP/AVIF — такие же обёртки. Своего DEFLATE тоже нет:crates/network/src/flate.rs— этоflate2, WOFF1 распаковываетсяminiz_oxide. Все растровые кодеки и сжатие — provisional-категория ниже;- TrueType-парсинга (
lumen-font: cmap/glyf/CFF/COLR/CPAL/fvar/gvar — variable и color fonts), подбора шрифтов и растеризации глифов. Text shaping закрытrustybuzz(LIB-1, 2026-08-31, production default с LIB-2, 2026-08-31; см. таблицу Permanent exceptions ниже) — свой GSUB/GPOS движок (GSUB 1/4 из 8, GPOS 1/2 из 9, без диакритики и сложных письменностей) удалён целиком вLIB-3(2026-09-01),rustybuzz— единственныйTextShaperза trait-anchorlumen_core::ext::TextShaper; - движка адблок-фильтров;
- 2D-растеризации поверх GPU-абстракции;
- ephemeral KV-хранилища (in-memory, для тестов и session-scope данных);
- IPC, async-примитивов;
- UI-фреймворка (иммедиат-режим поверх своих paint-примитивов);
- собственных MD5 / SHA-256 (для HTTP Digest, не security-критично — challenge-response, не KDF), Base64;
- knowledge layer §12 — это пользовательская ценность Lumen, не делегируется внешним библиотекам.
Bidi (UAX #9), line breaking (UAX #14), segmentation (UAX #29), normalization (UAX #15) — формально были в «своё», но писать свои Unicode-таблицы — это годы работы с обновлениями при каждом релизе Unicode. Переходят в provisional через icu4x.
Это единственные deps, для которых принципиально нет смысла писать своё. Каждая прячется за trait в lumen-core::ext.
| Crate | Что покрывает | Trait-anchor | Почему не сами |
|---|---|---|---|
winit |
OS event loop, окна, ввод | WindowingBackend |
Win32 + X11 + Wayland + AppKit — ~50–100k LOC платформенно-специфичных багов и behaviour quirks |
wgpu |
GPU API (Vulkan / Metal / DX12 / GL) | RenderBackend |
4 разных API, разные семантики, driver-баги. Свой = годы работы и регрессий |
rustls + webpki-roots |
TLS, X.509, X25519, AES-GCM, HKDF; webpki-roots — bundle корневых CA-сертификатов (Mozilla CA bundle). Без него HTTPS не валидируется. |
TlsBackend |
Универсальное правило безопасности: не пишите свой crypto. rustls — аудит + формальная верификация частей кода. webpki-roots — pure data + lookup, partner-crate к rustls |
rustls-pemfile |
PEM-декодирование X.509-сертификатов и приватных ключей — используется tls::trusted_root_store() (crates/network/src/tls/mod.rs) для загрузки дополнительного CA из файла, названного LUMEN_EXTRA_CA_CERT (BUG-785) |
TlsBackend (тот же, что rustls) |
Partner-crate к rustls (тот же upstream org). Своя реализация base64/PEM-разбора сертификатных данных — тот же «не пишите свой crypto» антипаттерн |
aes-gcm + aes (RustCrypto) |
AEAD AEAD_AES_128_GCM + сырой AES-128 блок для QUIC packet protection (RFC 9001 §5.3/§5.4) в lumen-network::h3; тот же aes-gcm уже под Web Crypto (lumen-js) и шифрованием хранилища (lumen-storage) |
нет отдельного (низкоуровневый примитив под QUIC) | То же правило «не пишите свой crypto» (Exception #3). Pure-Rust RustCrypto, без native-кода; ручная реализация AEAD/AES — security antipattern |
cbc (RustCrypto) |
AES-CBC режим с PKCS7 padding для SubtleCrypto AES-CBC (lumen-js::subtle_crypto, W3C WebCrypto §17.7); оборачивает aes 0.8 |
нет отдельного (примитив режима шифрования под WebCrypto) | Pure-Rust RustCrypto cipher-mode wrapper; ручная реализация CBC с padding — security antipattern |
ctr (RustCrypto) |
AES-CTR stream cipher (Ctr128BE) для SubtleCrypto AES-CTR (lumen-js::subtle_crypto, W3C WebCrypto §17.8); оборачивает aes 0.8 |
нет отдельного (примитив режима шифрования под WebCrypto) | Pure-Rust RustCrypto; ручная реализация CTR — security antipattern |
x25519-dalek (dalek-cryptography) |
X25519 (Curve25519) ECDH для TLS 1.3 key_share (RFC 7748 / RFC 8446 §4.2.8) в lumen-network::h3::key_agreement — превращает пару ephemeral KeyShareEntry в (EC)DHE shared secret для tls_schedule::handshake_secret |
нет отдельного (низкоуровневый примитив под QUIC/TLS) | То же правило «не пишите свой crypto» (Exception #3). Constant-time скалярное умножение, pure-Rust, без native-кода; ручная реализация Curve25519 — security antipattern |
ed25519-dalek (dalek-cryptography) |
Ed25519 (EdDSA над Curve25519, RFC 8032) — верификация подписи схемы ed25519 в TLS 1.3 CertificateVerify (RFC 8446 §4.2.3) в lumen-network::h3::tls_cert_verify::ed25519_verify (peer-аутентификация QUIC/HTTP/3). Переиспользует curve25519-dalek уже в дереве (транзитивно через x25519-dalek) |
нет отдельного (низкоуровневый примитив под QUIC/TLS) | То же правило «не пишите свой crypto» (Exception #3). Verify-only, constant-time, pure-Rust dalek; ручная реализация Ed25519 — security antipattern |
rsa (RustCrypto) |
(1) RSASSA-PSS с SHA-256 — верификация подписи схемы rsa_pss_rsae_sha256 в TLS 1.3 CertificateVerify (RFC 8446 §4.2.3, RFC 8017 §8.1) в lumen-network::h3::tls_cert_verify::rsa_pss_sha256_verify. (2) W3C WebCrypto SubtleCrypto — RSA-OAEP encrypt/decrypt (P3-webcrypto slice 3), RSA-PSS sign/verify, RSASSA-PKCS1-v1_5 sign/verify + generateKey/importKey/exportKey для всех трёх схем в lumen-js::subtle_crypto. Переиспользует sha2 уже в дереве |
нет отдельного | То же правило «не пишите свой crypto» (Exception #3). Pure-Rust RustCrypto, без native-кода; ручная реализация RSA — security antipattern |
rand_core (RustCrypto) |
OsRng (OsRng::default()) для генерации RSA-ключей (rsa::RsaPrivateKey::new) в lumen-js::subtle_crypto::generate_key (W3C WebCrypto SubtleCrypto). Companion crate к rsa — тот уже транзитивно тянет rand_core; явный dep для признака getrandom |
нет отдельного (примитив CSRNG под keygen) | RustCrypto; без getrandom feature OsRng недоступен на Windows |
p384, p521 (RustCrypto) |
ECDSA P-384/P-521 — верификация подписи схем ecdsa_secp384r1_sha384 / ecdsa_secp521r1_sha512 в TLS 1.3 CertificateVerify (RFC 8446 §4.2.3) в lumen-network::h3::tls_cert_verify::ecdsa_p384_sha384_verify / ecdsa_p521_sha512_verify (peer-аутентификация QUIC/HTTP/3; более крупные NIST-сиблинги p256-схемы). Тот же RustCrypto ecdsa/signature v2, что и p256 |
нет отдельного (низкоуровневый примитив под QUIC/TLS) | То же правило «не пишите свой crypto» (Exception #3). Verify-only, pure-Rust RustCrypto, без native-кода; ручная реализация ECDSA — security antipattern |
SQLite (rusqlite с bundled feature) |
Персистентное хранилище: history, bookmarks, notes, read-later, cookies-TTL, профили. FTS5 для §12.1 полнотекстового поиска. | StorageBackend + KnowledgeStore |
25 лет TH3-тестирования (100% MC/DC branch coverage), стандарт индустрии браузеров (Firefox/Chromium/Safari). Цена ошибки persistent storage асимметрична — молчаливая порча данных пользователя; та же логика, что у crypto. FTS5 закрывает §12.1 без своего inverted index |
Долгосрочная стратегия: pure-Rust storage (redb + tantivy). SQLite остаётся permanent exception на Phase 0–2. Однако
rusqliteсbundledтянет ~250 КБ C-кода, который нельзя аудировать средствами Rust — это противоречит принципу «свой код = прозрачность». Целевая архитектура (Phase 3+): redb (pure Rust, ACID copy-on-write B+tree, нольunsafe, используется вcargo) для key-value подсистем (localStorage, sessionStorage, IndexedDB, HTTP cache) + tantivy (Rust-native FTS) для полнотекстового поиска §12.1. Оба заStorageBackend/KnowledgeStoretrait — drop-in замена. Graduation criterion: замерить p99 latency SQLite WAL vs redb на реальной нагрузке; если SQLite < 1 мс — миграция не срочна, но остаётся целью ради чистоты стека. |rayon| Work-stealing parallel iterator framework. ADR-016 M4.1: параллельныйcompute_styleдля независимых дочерних узлов flex/grid/table item containers вlumen-layout::box_tree. | нет (внутренний примитив параллелизма) | 8+ лет в production, правильный NUMA-aware work-stealing; своя реализация — недели без ценности для идентичности Lumen. Параллелизм layout — не ядро браузерного engine | |unicode-bidi,unicode-bidi-mirroring| UAX #9 Unicode Bidirectional Algorithm (правила P2–I2) и таблицаBidi_Mirroring_Glyph(правило L4) — свойстваdirection/unicode-bidiвlumen-layout::bidi.unicode-bidiуже был в дереве черезlumen-encoding(Icu4xUnicodeProvider::bidi_runs),unicode-bidi-mirroring— транзитивно через text-стек | нет (чистые Unicode-таблицы, не заменяемая подсистема) | Алгоритму нужно свойствоBidi_Classкаждой кодовой точки Unicode; своя таблица — это генератор из UCD и её ежегодная синхронизация, без какой-либо ценности для идентичности Lumen. Крейты — pure-Rust данные + ~1500 строк правил, безunsafeи без C | | JS engine (v8v150.1.0 — дефолт с cutover S12, ADR-018, 2026-07-14, единственный движок с S12b-F1, 2026-08-04;rquickjsполностью удалён из Cargo.toml/Cargo.lock срезом S12b-F4, 2026-08-04) | Исполнение JavaScript |JsRuntime| V8 — 15 лет, миллиарды долларов, сотни инженеров. QuickJS был движком Phase 0–2; S0 go/no-go PASS 2026-07-13, cutover S12 2026-07-14. Новый код — только против V8-пути или движко-независимого шима (WEB_API_SHIM). | |rustybuzz(0.14.1,crates/engine/font, обязательная зависимость сLIB-3) | Text shaping — OpenTypeGSUB/GPOSlayout engine: mark attachment (GPOS 4), Arabic joining (GSUB 5/6/8), Indic reordering. ЕдинственныйTextShaper: свой GSUB/GPOS движок (U-2, GSUB 1/4 из 8, GPOS 1/2 из 9) удалён вLIB-3(2026-09-01) после того, какLIB-2(2026-08-31) продержал его продакшн-дефолтом через полный цикл пересъёмки graphic-tests/CPU/paint снимков без дрейфа. Уже был в дереве транзитивно черезfemtovg(её собственный, неиспользуемый text-путь) той же версии0.14.1— подключение не добавило новых версий зависимостей ниrustybuzz, ниttf-parser|lumen_core::ext::TextShaper| Таблицы OpenType, решение принимает спека (ADR-027) | |ttf-parser(0.21.1, транзитивно черезrustybuzz) | Парсер таблиц шрифта дляrustybuzz. Свой парсер (lumen-font::face) остаётся — растеризация, метрики, variable/color fonts читает он; оба парсера ленивые и заимствуют одни и те же байты шрифта без копирования, второй набор офсетных структур в памяти — не второй набор байтов шрифта | нет отдельного (внутренняя зависимостьrustybuzz) | Уходит только вместе сrustybuzz| |resvg/usvg(=0.44.0 точно, не последняя 0.48 —crates/engine/image, обязательная зависимость сLIB-4, 2026-09-01) | Растеризация внешнего SVG (<img src=*.svg>,background-image: url(*.svg)) —lumen_image::decode_svg(src/svg.rs), диспетчеризуется изdecode_rawпо сигнатуре наравне с PNG/JPEG/GIF/WebP/AVIF. Свой SVG-движок (box_tree/svg.rs/svg_path.rs) рисует нольlinearGradient/radialGradient/clipPath/mask/filter/pattern/marker(измерение ADR-027) — растровый логотип с градиентом выходил плоским. Версия зафиксирована точно, потому что еёtiny-skia— 0.11.4, та же, что уже несётlumen-paint'scpu-render:cargo tree -i tiny-skiaдержит одну версию при обоих фичах разом. Фичаraster-imagesвключена (вложенный<image>),text/system-fontsвыключены (свои шрифты — детерминизм графгейта важнее рендера текста внутри SVG) | нет отдельного (decode_raw's единая точка диспетчеризации по сигнатуре) | Таблицы SVG 1.1/2, решение принимает спека (ADR-027) | |url(2.5.8,crates/core, обязательная зависимость сLIB-6, 2026-09-01) | Scheme/host/path/query/fragment splitting, percent-encoding normalization, dot-segment removal, relative-reference resolution — весь WHATWG URL Standard state machine, вызывается изlumen_core::url::Url(inner: url::Url). Своя ~370-строчная реализация проходила 41.95%urltestdata.json(LIB-0), сосредоточенных в двух целиком отсутствующих ветках алгоритма (IPv6-литералы[...], forbidden/control host code points) — новая проходит 81.86%.Url::host()НЕ берёт значение изurl: WHATWG-парсер всегда ASCII/IDNA-нормализует host (Punycode + lowercase), а адресная строка (crates/shell/src/address_bar.rs::guard_display_text, DS-6) ищет в тексте ТОЧНУЮ подстроку, которую ввёл пользователь —host()остаётся своей raw-экстракцией;host_ascii()/IDN homograph-проверки остаются наlumen-core::idn/lumen-core::punycode, как и решено вLIB-6| нет отдельного (crate::url::Url— сам swap-point) | Конечный автомат WHATWG, решение принимает спека (ADR-027) |
Trait-anchor у каждого — в lumen-core::ext. Подключаем по мере того, как фаза реально упирается в задачу. Список открыт.
| Crate (кандидаты) | За что | Trait-anchor | Phase | Graduation criterion |
|---|---|---|---|---|
zune-jpeg, image-webp, узкий image без default features |
Декодирование JPEG / WebP / GIF в RGBA. PNG остаётся свой в lumen-image |
ImageDecoder |
1 | Едва ли когда-то. Форматы стабильные, без архитектурной ценности; цена реализации (JPEG — DCT+Хаффман+chroma subsampling+progressive; WebP — VP8/VP8L) непропорциональна выгоде |
image (feature avif-native, за cargo-фичей avif в lumen-image, не в default; GAP-avif срез 1, 2026-09-21) |
Декодирование AVIF в RGBA через её avif-native (dav1d C + mp4parse) |
ImageDecoder (AvifImageDecoder) |
1 | Едва ли. dav1d-sys требует системный dav1d через pkg-config — без него cargo build --features avif падает на build-скрипте dav1d-sys (проверено: нет pkg-config в тулчейне). Чистого-Rust AV1-декодера с готовой ISOBMFF-обвязкой нет (rav1d публикует только unsafe C-ABI) — своя реализация непропорциональна выгоде, пока AVIF не станет обязательным форматом |
jxl-oxide (lumen-image, не за фичей — в default с GAP-avif срез 3, 2026-09-21) |
Декодирование JPEG XL в RGBA (jxl.rs::decode_jxl) |
ImageDecoder (JxlImageDecoder) |
1 | Едва ли. Чистый Rust, без cmake/meson/nasm/pkg-config (проверено cargo tree) — та же категория цены/выгоды, что у JPEG/WebP выше, но декодер CMYK/CMYKA и анимацию не покрывает; расширить их своими силами, если появится реальный спрос |
weezl (прямая зависимость lumen-image с 2026-08-20, до этого — транзитивная через gif) |
LZW-распаковка пикселей GIF-кадра собственным циклом (lumen_image::gif::lzw_decode_into) вместо gif::FrameDecoder, который на кадре с оборванным LZW-потоком не возвращает управление (BUG-787) |
ImageDecoder (тот же, что у GIF-декодера) |
2 | Уйдёт только вместе с gif: пока GIF-контейнер разбирает он, weezl в дереве всё равно, и отдельная замена ничего не убирает. Свой LZW (спек GIF §22, ~200 строк) осмыслен лишь если понадобится побитовый контроль сверх того, что даёт decode_bytes |
icu4x (выборочные модули: segmentation, line-break, bidi, normalization, CLDR-минимум) |
Unicode UAX #9 / #14 / #29 / #15 + локалевые таблицы | UnicodeProvider |
1–2 | Реалистично — никогда. Unicode Consortium = «универсальное правило безопасности» для Unicode, аналогично rustls для crypto. Своя реализация = годы поддержки таблиц на каждом релизе Unicode |
brotli-decompressor |
Brotli decompression для HTTP Content-Encoding: br |
расширение ContentDecoder |
1–2 | Едва ли. Формат RFC 7932 стабилен, своя реализация = недели с собственным dictionary |
ruzstd / zstd-safe |
Zstandard decompression для HTTP Content-Encoding: zstd (Cloudflare и nginx уже отдают; через 1-2 года будет распространено) |
расширение ContentDecoder |
1–2 | Реалистично — никогда. Формат RFC 8478 стабилен, без архитектурной ценности; своя реализация = недели |
publicsuffix (или собственный загрузчик publicsuffix.org/list/public_suffix_list.dat) |
Public Suffix List для cookie domain matching (example.co.uk ≠ co.uk), eTLD+1 расчёта, SameSite=Strict boundary |
PublicSuffixList |
1 | Едва ли. Данные обновляются раз в неделю-месяц, формат — простой текст; собственный loader тривиален, но crate избавляет от поддержки парсера |
idna |
Полный UTS#46 mapping table для IDN (ß, ZWJ, контекстные правила) | IdnaProvider (на базе текущего Url::host_ascii()) |
1–2 | Когда найдём real edge-case, который наш str::to_lowercase-Punycode не покрывает |
hyphenation |
Перенос слов (TeX-словари, включая русский) | HyphenationProvider |
2 | Phase 2+ при типографике. Словари можно переписать на свой формат, но low priority |
woff2 |
Распаковка WOFF2 в TTF | расширение FontFormat |
2 | Phase 2 при WebFonts. Формат стабилен, маловероятно писать своё |
hunspell-rs / spellbook |
Spell-check (русская морфология обязательна) | SpellChecker |
3 | Phase 3 при spell-check. Морфология русского сложна, цена своей реализации перекрывает выгоду |
quinn |
HTTP/3 / QUIC | расширение NetworkTransport |
3 | Реалистично — никогда. QUIC = год+ работы (congestion control, packet loss recovery, 0-RTT, key updates) |
windows-sys (lumen-network, cfg(windows), с 2026-10-13; уже в графе у lumen-storage/lumen-shell/lumen-a11y) |
Чтение корней доверия ROOT и Disallowed из хранилища Windows (CertOpenStore/CertEnumCertificatesInStore, COMPAT-TRUST-OSROOTS) |
нет — единственный потребитель tls/os_roots.rs |
1 | Постоянная, пока Windows — поддерживаемая платформа |
windows 0.58 (windows-rs, lumen-media-native, cfg(windows), с 2026-10-15; версия та же, что у gpu-allocator) |
COM-интерфейсы Media Foundation (IMFTransform, IMFSample, IMFMediaType, IMFActivate): H.264/HEVC/AAC из ОС (COMPAT-MEDIA-OSDEC-WIN) |
VideoBackend/AudioBackend реестра декодеров |
1 | Постоянная, пока декодеры ОС — путь для патентованных кодеков (ADR-035 п.3); функции mfplat.dll не линкуются, а грузятся LoadLibraryExW |
redb |
Pure Rust ACID key-value (copy-on-write B+tree). Альтернативный storage backend для горячих key-value (localStorage, IndexedDB, HTTP cache) | StorageBackend |
2–3 | Замерить p99 latency SQLite WAL vs redb на реальной нагрузке localStorage/IndexedDB. Если SQLite < 1 мс — не нужен |
tantivy |
Rust-native полнотекстовый поиск. Замена SQLite FTS5 для §12.1 knowledge layer при миграции на pure-Rust storage | KnowledgeStore |
3+ | Только вместе с redb — при решении полностью отказаться от SQLite C-кода |
mp4parse 0.17 (MPL-2.0, Mozilla, используется в Firefox), matroska-demuxer 0.8 (Zlib/MIT/Apache), ogg 0.8 (BSD-3) + lewton 0.10 (MIT/Apache) — crates/engine/media-demux, с 2026-10-15 (UX-VIDEO-DEMUX, ADR-035 п.2). Контейнеры MP4/ISOBMFF, WebM/Matroska, Ogg — формат определяет спека, не мы (ADR-027). provisional: заменяются своим разбором, если упрёмся в их пределы (mp4parse не знает HEVC/VP9/AV1 в stsd — эти боксы разбираем сами; читатель Matroska не отдаёт ReferenceBlock и перематывает «после метки» — индекс ключевых кадров свой) |
lumen_core::ext::VideoDecoder (пакеты уходят бэкендам кодеков реестра) |
1–2 | Граница пересматривается в UX-VIDEO-NATIVE: если свои обходы станут больше самих читателей | |
rav1d 1.1 (BSD-2, Rust-порт dav1d) — crates/engine/av1 (lumen-av1), с 2026-10-15 (UX-VIDEO-AV1, ADR-035 п.2; до этого лежал в lumen-image только для AVIF). Единственный встроенный AV1-декодер на всех платформах: AVIF-картинки и видео. По умолчанию без asm (не нужен nasm); релизные сборки — фича av1-asm (nasm при сборке на x86), ≈3,5× быстрее (замер). |
lumen_core::ext::ImageDecoder (AVIF) и lumen_core::ext::VideoDecoder (бэкенд реестра) |
1–2 | permanent: AV1 — реальный веб-кодек (YouTube, VK Видео, AVIF); пересматривается, только если появится аппаратный AV1 на всех платформах | |
Ручной FFI-слой (opaque-указатели) поверх FFmpeg shared-dev, БЕЗ ffmpeg-next/ffmpeg-sys-next (статус: crate landed под feature ffmpeg (off by default), не подключён к crates/js, решение — ADR-030, 2026-09-19; с 2026-10-12 только необязательный бэкенд для разработчиков, в выпуск не входит — видео декодируется без FFmpeg, ADR-035) |
Декодирование video/mp4/video/webm/video/ogg (GAP-MEDIADECODE) — сегодня декодируется только анимированный GIF. Пользователь выбрал «FFmpeg целиком» из трёх вариантов кодек-стратегии (альтернатива — узкий набор кодеков или внешний процесс-декодер) |
lumen_core::ext::VideoDecoder/VideoDecodeSession реализованы в crates/engine/media-ffmpeg (FfmpegVideoDecoder/FfmpegSession), срез 4 |
Таблицы видео-кодеков (H.264/VP8/VP9/AV1/…), решение принимает спека (ADR-027). ffmpeg-sys-next's bindgen-генерация FFI на целевой x86_64-pc-windows-msvc даёт несовпадающий layout для набора структур FFmpeg И libc's struct tm (см. ADR-030) — этот путь остаётся отклонён. Ревизии 2026-09-19 (срезы 2-3) подтвердили живым прогоном в scratch-PoC (D:\Temp\ffmpeg-ffi-poc, не коммитился), что обходной путь работает целиком, включая декодирующий цикл и sws_scale. Срез 4 перенёс это в реальный крейт crates/engine/media-ffmpeg: hand-rolled FFI (src/ffi.rs), VideoDecoder/VideoDecodeSession impl поверх custom AVIOContext (декодирует &[u8] в памяти, не путь на диске — обязательное условие для сетевого/Blob-ответа <video>), av_seek_frame+avcodec_flush_buffers для frame_at(secs), build.rs резолвит FFMPEG_DIR. Крейт спрятан за feature ffmpeg (default off): без неё cargo build --workspace не требует FFmpeg вовсе ни на одной машине. Живые тесты (cargo test -p lumen-media-ffmpeg --features ffmpeg, нужен FFMPEG_DIR + DLL на PATH) декодируют 2x2-green.webm (VP8/9) и test.mp4 (H.264) из tests/wpt/. Не сделано: подключение к crates/js/src/video_bindings.rs's resource-selection алгоритму (следующий срез), лицензионная заметка про GPL-компоненты FFmpeg-дистрибутива (не cargo-deny-проблема — в Cargo.lock не появилось ни одной новой лицензируемой Rust-зависимости, поскольку FFI ручной; риск — в связанных DLL, а не в графе Cargo) |
|
cc (build-dependency lumen-js, с 2026-09-19) |
Сборка ОДНОЙ C++-единицы трансляции crates/js/cpp/undetectable.cc — локального биндинга к v8::ObjectTemplate::MarkAsUndetectable() и SetCallAsFunctionHandler() (GAP-DOCALLDDA/BUG-1057). Оба символа уже лежат в прекомпилированной rusty_v8.lib, но Rust-обёрток к ним крейт v8 не даёт, а патч его binding.cc потребителю не помогает: тот файл компилируется только под V8_FROM_SOURCE |
— (вызов хост-тулчейна C++; тем же cc пользуется и сам крейт v8) |
3 | Удаляется целиком, как только denoland/rusty_v8#2078 выйдет в релизе крейта — обёртка тогда приедет из самого v8 |
Принципы работы с provisional-категорией:
- Trait-anchor обязателен. Перед добавлением dep в
Cargo.tomlсначала появляется trait вlumen-core::extи default-имплементация (наша, заглушечная или wrapped-around готового crate). Это гарантирует, что замена в будущем — drop-in, без переписывания потребителей. - Подключение «по событию», не превентивно. Не добавляем
icu4xпока bidi реально не понадобится; не добавляемquinnпока HTTP/3 не на повестке. - Annual review. Раз в год — проход по provisional-списку: какие graduation criteria сработали → завести задачу на свой код; какие нет → продлить.
- Расширение списка — через DECISIONS.md. Каждое добавление в provisional — новая запись в DECISIONS.md с обоснованием и graduation criterion.
Эти крейты регулярно обсуждаются как «возьми готовое», но для всех решение — отвергнуть. Это идентичность проекта: места, где решение принимаем мы (ADR-027).
→ свой HTML-парсер по HTML5 spec (см. §6.1).html5ever→ свой CSS-парсер по CSS Syntax L3 (§6.2).cssparser+selectors→ свой каскад и computed values (§6.4).stylo→ свой layout: block, inline, flex, grid (§6.5).taffy→ свой HTTP/1.1 и HTTP/2 поверхhyperrustls+ std (только HTTP/3 через provisionalquinn).→ свой DNS-резолвер с DoH/DoT поверхhickory-resolverrustls.→ свои таблицы декодирования (cp1251, KOI8-R, CP866, UTF-8, ASCII, Win-1252).encoding_rs→ свои homograph checks для IDN.unicode-security(Brave) → свой filter matcher.adblock→ своя реализация readability heuristics с настройкой под кириллицу (§10.9).readability→ своя компактная binary serialization для IPC.postcard+serde→ свой минимальный async-исполнитель поверх std + epoll/kqueue/IOCP (или single-threaded на старте).tokio→ свой иммедиат-режим UI поверхegui/iced/Slintwgpu-примитивов из paint-крейта.для PNG — запись отменена 2026-08-31. Решение не выполнено и выполнено не будет: своего PNG-декодера нет (обёртка надflate2/miniz_oxidezune_png), своего DEFLATE нет (flate2вcrates/network/src/flate.rs,miniz_oxideв WOFF1). Историческая запись — DECISIONS.md.
Покинули этот список 2026-08-31 по ADR-027 — во всех четырёх случаях решение принимает спека, а не мы:
| Крейт | Почему ушёл | Задача |
|---|---|---|
rustybuzz |
Свой шейпер закрыт задачей U-2 как done и покрывает GSUB 1/4 из 8, GPOS 1/2 из 9; диакритика не прикрепляется, сложных письменностей нет |
LIB-1…LIB-3 |
ttf-parser |
Приходит транзитивно с rustybuzz. Свой парсер таблиц остаётся — растеризация, метрики, variable/color fonts наши |
LIB-1 |
resvg / usvg |
Исходная причина (до замены): в пути отрисовки SVG ноль упоминаний linearGradient/radialGradient/url(#…); нет clipPath, mask, filter, pattern, marker, <image>. Текущее состояние — см. Permanent exceptions выше |
LIB-4 (done 2026-09-01, внешний SVG через сам resvg/usvg), LIB-5 (done частично 2026-09-01 — только градиенты inline SVG, свой tree/cascade сохранён: публичное API usvg pub(crate)-закрыто, целиком непригодно как библиотека), LIB-9 (done частично 2026-09-01 — <mask> inline SVG, wgpu-путь пока с багом BUG-936) |
url |
Конечный автомат WHATWG против ~370 своих строк; официальный корпус urltestdata.json уже лежит в tests/wpt/url/resources/ |
LIB-0 (done), LIB-6 (done 2026-09-01, обязательная зависимость — см. Permanent exceptions выше) |
tiny-skia |
Уже зависимость (crates/engine/paint/Cargo.toml, бэкенд cpu-render) — запись была неверна фактически |
— |
Инструменты, которые не попадают в бинарь, но используются на CI / при разработке:
cargo-deny— аудит лицензий и CVE четырёх exceptions и их транзитивных зависимостей.cargo-vet— supply-chain reviews.cargo-dist— упаковка релизов (опционально).cross— кросс-компиляция на CI.cargo-hakari+workspace-hack(internal crate) — feature-unification: 55 общих транзитивных зависимостей пришпилены к единому набору фич; устраняет перекомпиляцию при переключении между-p lumen-shellи-p lumen-driver. Категория: постоянная dev-инфраструктура; публикации нет;workspace-hack— path-dep только внутри workspace. Добавлено 2026-07-13 (§3.4docs/build-speed.md).tracy-client— визуальный профайлер (Tracy GUI, https://github.com/wolfpld/tracy), фичаtracy(lumen-core/lumen-layout/lumen-shell), не в default. В отличие от остальных пунктов этого раздела — МОЖЕТ попасть в собранный бинарь, но только при явном--features tracy; обычная сборка (cargo build -p lumen-shell) не тянет его вовсе (dep:tracy-clientопционален, макросlumen_core::tracy_zone!компилируется в no-op без фичи). Категория: provisional (см. workspaceCargo.toml, комментарий над версией). Добавлено 2026-07-15 (BUG-284 perf investigation,docs/plan/security-performance.md§14.3).
Если в коммите / Pull Request добавляется новая зависимость в Cargo.toml, в описании обязателен пункт:
Why this dependency: <обоснование, почему свой код тут категорически неуместен — иначе пишем сами>
CI-чек на новые [dependencies]-строки добавим, когда появится remote.
- Rust edition 2024, MSRV — последний stable (сейчас 1.95).
cargoworkspace.- Сборка релизов —
xtask-крейт, опциональноcargo-distповерх.