MOffice

Открытый код для форматов, Sheets и данных (Codecs, meridian-calc, Base)

Отчёт исследования, 2026-10-04. Область: чтение/запись форматов, CFB и шифрование Office, движок таблиц и функций, числовые форматы, потоки данных, поиск решения, статистика, даты, десятичные; MOffice Base. Правила и классы лицензий — docs/research/BRIEF.md, docs/12-license-policy.md.

1. Выводы

Главное. Для Sheets и кодеков есть готовая основа классов 0–1 почти на всё, кроме OneNote, Visio/Publisher/iWork (там только MPL-библиотеки — решение владельца — или своя работа по спецификациям с разрешительными референсами). Три находки меняют component-map.md: (1) outlook-pst — эталонная реализация [MS-PST] от самой Microsoft на Rust, MIT; (2) jetdb — чтение .mdb/.accdb на чистом Rust, MIT OR Apache-2.0; (3) formualizer — второй движок таблиц на Rust (MIT OR Apache-2.0) с инкрементальным графом зависимостей и многопоточным пересчётом, то есть ровно с тем, чего нет у IronCalc. Ещё одна поправка: formulajs и Univer почти не нужны как источник функций. Скрипт сравнения показал, что IronCalc уже покрывает 492 из 518 имён каталога (§3.1–3.2), поэтому ценность этих двух проектов — в тестах.

Базис для оценки экономии. В 08-roadmap.md трудоёмкость по эпикам не разбита, поэтому база эпика = численность подкоманды × длительность эпика (инкремент = 6 недель). Получается так: E2.2 «Движок формул» ≈ 21 чел.-мес. (2,5 Rust × I05–I10); E2.4 «Кодеки Sheets» ≈ 19 (2 × I05–I11); E1.4 «Кодеки Write» ≈ 21 (2,5 × I03–I08); E3.4 «Кодеки Slides/Draw» ≈ 24 (2,5 × I09–I15); E5.6 «Кодеки PIM» ≈ 17 (2 × I17–I22); E5.4 Base ≈ 24, из них Rust ≈ 10.

# Что берём Лиц. / класс Стратегия Куда в MOffice Экономия, чел.-мес. (эпик)
1 IronCalc: 492 работающие функции (P0 — 99,4 %), парсер A1/R1C1 с локалями, LET/LAMBDA, spill, структурированные ссылки, 2 768 тестов и 211 эталонных xlsx MIT OR Apache-2.0 / 1 fork → meridian-calc Kernel/формулы, Sheets 11–13 (E2.2)
2 Apache POI: записи HSSF и PTG, модель HWPF и sprm, записи HSLF, DDF (OfficeArt), HPSF Apache-2.0 / 1 port codec-msbinary (doc/xls/ppt) 9–12 (E1.4, E2.4, E3.4)
3 Стек Base: rusqlite + SQLCipher, sqlparser-rs, tokio-postgres / mysql_async / tiberius / odbc-api; FastReport как референс полос отчёта MIT, BSD-3, Apache / 1 adopt + ref meridian-db, meridian-base 2–3 (E5.4; драйверы и sqlparser уже заложены в base.md)
4 outlook-pst (Microsoft) — [MS-PST] на Rust MIT / 1 adopt codec-mail/pst 4–5 (E5.6)
5 onenote_parser (onenote.rs) MPL-2.0 / 2 adopt без правок, если разрешит владелец; без разрешения — своя реализация, pyOneNote (Apache) как референс codec-onenote 4–5 с разрешением / ≈1 без него (E5.6)
6 jetdb (чтение Jet3…ACE17, запросы, VBA, шифрование) + jackcess (сложные типы, выражения, свойства) MIT OR Apache-2.0; Apache-2.0 / 1 fork + port частей codec-access 3–4 (E5.6)
7 Polars, arrow/parquet, csv, encoding_rs, chardetng MIT, Apache, Unlicense / 0–1 adopt потоки данных, мастер CSV, «большой режим» 3–4 (E2.4, Sheets 1.6)
8 HiGHS + good_lp (без coin_cbc), Clarabel, argmin MIT, Apache / 1 adopt Поиск решения 2–3 (Sheets 1.6)
9 numbers-parser, iWorkFileFormat, litchi — референсы IWA MIT, MIT, Apache-2.0 / 1 ref / port схем codec-iwork 2–3 (E2.4, E3.4)
10 SheetJS SSF (+ ≈2,4 млн строк эталонов), office-crypto + ms-offcrypto-writer + msoffcrypto-tool, formualizer (граф), calamine Apache, MIT / 1 port / adopt / ref meridian-numfmt, offcrypto, граф meridian-calc, быстрый импорт 4–6 вместе (E2.2, E1.4, E2.4)

Итого ≈ 44–58 чел.-мес. против базиса roadmap (41–54, если владелец не разрешит MPL для OneNote); с мелочами из §2 — ≈ 47–62. Кроме того, снимается главный риск фазы 2: по оценке §3.1, 500 функций «с нуля» — это 28–35 чел.-мес., а в roadmap на весь E2.2 заложено ≈ 21. Высвобожденные 1–2 Rust FTE стоит отдать на сводные таблицы и Chart: это риск «сводные объёмнее оценки» из §3.2 roadmap.

2. Таблицы по подобластям

Данные о лицензиях, звёздах, загрузках и датах взяты из oss-verified.tsv (проверка 2026-10-04); для того, чего там нет, стоит пометка. Даты последнего коммита — по клонам (git log -1) или по pushed_at. Сокращения: ★ — звёзды GitHub, «загр.» — загрузки с crates.io; стратегии — по BRIEF.

2.1 OOXML, ODF и общий фундамент кодеков

Кандидат SPDX (кл.) ★ / загр. Коммит Язык Что даёт MOffice Стр. Что пишем сами, риски Эк.
zip2, quick-xml, roxmltree MIT; MIT; MIT OR Apache (1) 287M; 447M; 80M 2026-10 / 08 / 09 Rust codec-core: ZIP64, потоковый XML, мелкие DOM adopt — (в базе)
rust_xlsxwriter MIT OR Apache-2.0 (1) ★591 / 4,9M 2026-09-14 Rust эталон XML, который принимает Excel: диаграммы, условное форматирование, таблицы, спарклайны, проверка данных ref + fork модулей записи диаграмм и стилей только запись, без чтения и round-trip; модель чужая 1–1,5
umya-spreadsheet MIT (1) ★483 / 1,2M 2026-10-01 Rust готовые Rust-структуры сотен элементов SpreadsheetML (чтение и запись) ref медленный, модель не наша; брать только как донор схемы 0,5
IronCalc xlsx MIT OR Apache-2.0 (1) ★4,2k 2026-10-02 Rust импорт и экспорт стилей, условного форматирования, sharedStrings, метаданных dynamic arrays, префиксов _xlfn. fork частей нет диаграмм, сводных, проверки данных, изображений, защиты и round-trip (§3.1) 1
Open-XML-SDK MIT (1) ★4,6k 2026-09-16 C# машиночитаемые схемы всех элементов OOXML → генератор Rust-типов и валидатор ref (данные схем) генератор пишем сами 1
spreadsheet-ods MIT/Apache-2.0 (1) ★37 / 118k 2026-03-20 Rust чтение и запись ODS: стили, формулы строками ref / fork один автор; конвертер OpenFormula ↔︎ канон пишем сами 0,5–1
Apache OpenOffice (xmloff, oox, фильтры ww8/excel/ppt/rtf) Apache-2.0 (1) ★1,2k 2026-09-22 C++ единственный полный класс-1 код фильтров doc/xls/ppt/rtf/ODF/OOXML-импорта ref C++ на внутренних API AOO — только как референс поведения (в §3.4)
docx-rs, docx4j, python-docx, python-pptx, PptxGenJS, mammoth.js, ClosedXML, exceljs MIT / Apache-2.0 / BSD-2 (1) 0,5–15k 2024–2026 разные референсы разметки docx/pptx/xlsx ref — —

2.2 Бинарные форматы MS Office, CFB, шифрование

Кандидат SPDX (кл.) ★ / загр. Коммит Язык Что даёт MOffice Стр. Что пишем сами, риски Эк.
Apache POI Apache-2.0 (1) ★2,3k 2026-10-03 Java HSSF (xls), HWPF (doc), HSLF (ppt), DDF, HPSF, PTG, HDGF, HPBF, XDGF, HSMF port (§3.4) HWPF и HSLF лежат в «scratchpad» — запись слабая 9–12
calamine MIT (1) ★2,4k / 14,1M 2026-09-02 Rust быстрое чтение значений и формул xls/xlsx/xlsb/ods, извлечение VBA (vba.rs) adopt (R-сценарии) + fork vba.rs стилей нет — для полного кодека Sheets не годится 1–2
cfb MIT (1) 68M 2026-09-18 Rust чтение и запись CFB v3/v4 adopt — 0,5
office-crypto (проверено 2026-10-04) MIT (1) ★9 / 197k 2026-09-13 Rust расшифровка Agile/Standard (OOXML), RC4 CryptoAPI для doc и ppt adopt / fork нет xls RC4, XOR, Agile на SHA-1/256 0,5
ms-offcrypto-writer (проверено 2026-10-04) MIT OR Apache-2.0 (1) ★0 / 113k 2025-09-05 Rust запись Agile (AES-256/SHA-512) adopt один автор, тихий проект 0,3
msoffcrypto-tool MIT (1) ★625 2026-01-12 Python полный набор: xls RC4/XOR, doc RC4, ppt, Agile/Standard; тестовые файлы port недостающего (≈1,5 тыс. строк) — 0,5
olefile, oletools BSD-3; MIT+BSD (1) ★274; ★3,4k 2024 / 2026 Python разбор OLE, анализ VBA и макровирусов (для предупреждений о макросах) ref — —
libxls, xlrd, npoi BSD; BSD-3; Apache (1) ★0,5–6k 2026 C / Python / C# вторые референсы BIFF8: XF, форматы, кодировки ref — —
litchi (проверено 2026-10-04) Apache-2.0 (1) ★38 / 6,6k 2026-09-29 Rust doc/xls/ppt/IWA/ODF на Rust ref автор сам пишет «не для продакшена» —

2.3 RTF, Markdown, HTML, EPUB, FB2

Кандидат SPDX (кл.) ★ / загр. Коммит Что даёт MOffice Стр. Что пишем сами, риски
rtf-parser MIT (1) 188k 2026-06-11 токенизатор RTF ref модель упрощённая; свой ридер и писатель по RTF 1.9.1 (§3.4)
comrak BSD-2-Clause (1) ★1,7k / 8,4M 2026-09-23 GFM с AST и CommonMark-выводом → импорт и экспорт .md adopt —
pulldown-cmark MIT (1) ★2,7k / 166M 2026-09-30 быстрый потоковый Markdown (предпросмотр, Notes) adopt брать только один из двух (comrak или pulldown-cmark) для импорта
html5ever, ammonia MIT OR Apache (1) 117M; 17M 2026-09 / 10 разбор и санитизация HTML (Write, Mail) adopt CSS-каскад свой; не cssparser / lightningcss (MPL-2.0, см. §4)
epub-builder MPL-2.0 (2) 169k 2026-04-10 запись EPUB замена свой EPUB 3 R/W на zip + quick-xml (≈2 тыс. строк, 0,7 чел.-мес.)
epub (проверено 2026-10-04) GPL-3.0 (3) 268k 2025-10-29 чтение EPUB avoid см. §5
FB2 — — — — own крейтов нет; XML-схема FB2 — quick-xml, ≈1 тыс. строк, 0,3 чел.-мес.

2.4 PIM, Access, iWork, Visio, Publisher

Кандидат SPDX (кл.) ★ / загр. Коммит Язык Что даёт MOffice Стр. Риски Эк.
outlook-pst (проверено 2026-10-04) MIT (1) ★36 / 175k 2026-09-30 Rust [MS-PST] (NDB, LTP, Messaging), совместимость с mspst32.dll adopt полнота OST и записи не проверена 4–5
libpff LGPL-3.0 (2) ★368 2026-09-17 C PST/OST avoid (есть MIT) — —
java-libpst (проверено 2026-10-04) Apache-2.0 / LGPL — двойная, выбираем Apache (1) ★274 2022-07-11 Java второй референс PST ref заброшен —
msg_parser MIT (1) ★10 / 303k 2026-05-24 Rust .msg → поля и вложения adopt / fork один автор; лучше общий слой MAPI-свойств с PST 0,5
onenote_parser MPL-2.0 (2) ★86 / 23k 2026-08-06 Rust .one/.onetoc2, FSSHTTPB (OneDrive), чернила, формулы решение владельца (§3.6) — 4–5
pyOneNote (проверено 2026-10-04) Apache-2.0 (1) ★153 2024-07-11 Python разбор [MS-ONESTORE] ref неполный, не обновляется 1
jetdb (проверено 2026-10-04) MIT OR Apache-2.0 (1) ★13 / 8,4k 2026-10-03 Rust Jet3…ACE17: схема, строки, DDL, SQL запросов, VBA, свойства, расшифровка fork (§3.5) молодой (с 2026-02); все строки грузит в память 3–4 вместе с jackcess
jackcess Apache-2.0 (1) ★120 2026-09-13 Java эталон Jet/ACE, 86 тестовых баз port частей — (вместе с jetdb)
mdbtools GPL-2.0 (3) ★1,2k 2026-09-29 C — avoid упомянут в base.md и 04-file-formats.md — убрать (§7) —
numbers-parser (проверено 2026-10-04) MIT (1) ★257 2026-10-03 Python Numbers R/W, .proto-схемы IWA ref + port схем схемы извлечены из приложений Apple — юридическая проверка 2–3 вместе
iWorkFileFormat (проверено 2026-10-04) MIT (1) ★273 2016-06-08 док. описание контейнера IWA ref устарело (iWork 2013) (вместе)
libetonyek MPL-2.0 (2) ★19 2026-09-23 C++ Pages/Numbers/Keynote, включая iWork '09 замена — —
keynote-parser (проверено 2026-10-04) лицензия не указана (9) ★210 2026-08-09 Python Keynote не брать без лицензии — все права защищены —
POI HDGF / XDGF Apache-2.0 (1) — 2026-10-03 Java vsd: распаковка и чанки; vsdx: страницы, мастера, фигуры port VSD-геометрию дописываем сами (§3.7) 1–1,5
libvisio; libmspub MPL-2.0 (2) ★47; ★14 2026-09 C++ vsd; pub решение владельца / замена — —
POI HPBF Apache-2.0 (1) — 2026-10-03 Java извлечение текста .pub port рамки и раскладку пишем сами 0,5
evernote2md MIT (1) ★1,1k 2026-09-25 Go ENEX → Markdown ref — 0,2

2.5 Движок таблиц, функции, числовые форматы

Кандидат SPDX (кл.) ★ / загр. Коммит Язык Что даёт MOffice Стр. Риски Эк.
IronCalc MIT OR Apache-2.0 (1) ★4,2k / 124k (base) 2026-10-02 Rust 496 функций, парсер, spill, LET/LAMBDA, таблицы, форматер, 5 языков fork (§3.1) полный однопоточный пересчёт; нет 3D-ссылок, объединения и пересечения, внешних ссылок 11–13
formualizer (проверено 2026-10-04) MIT OR Apache-2.0 (1) ★187 / 3,4k 2026-09-30 Rust граф зависимостей, инкрементальный и параллельный (rayon) пересчёт, Arrow-хранилище, 418 функций + 19 алиасов, 4 263 теста ref + port графа и 3 функций движок 0.10 новый; хранение по столбцам Arrow ≠ наши чанки 1,5–2
Univer engine-formula Apache-2.0 (1) ★21,9k 2026-10-02 TS 516 имён (+22 заглушки), 475 spec-файлов / 5 563 проверки, описания на 17 языках ref (тесты) + port 4 функций русские описания похожи на справку Microsoft — не брать (§3.2) 1
formulajs MIT (1) ★820 2026-10-01 JS 437 имён, 3 084 проверки ref (тест-оракул) семантика JS-массивов ≠ Excel 0,5
SheetJS SSF Apache-2.0 (1) ★161 2023-02-22 JS движок числовых форматов Excel + эталоны port (§3.3) репозиторий заморожен (апстрим ушёл в монорепо SheetJS) 1–1,5
Grist Apache-2.0 (1) ★11,9k 2026-09-29 TS / Python формульные столбцы и их зависимости, trigger formulas, сводные таблицы ref (Base) формулы на Python — не наш язык 0,5
HyperFormula GPL-3.0 / коммерч. (3) ★2,8k 2026-09-29 TS — avoid — —
ixion / orcus MPL-2.0 (2) ★19 — C++ — не нужны есть класс 1 —

2.6 Данные, поиск решения, статистика, даты, десятичные

Кандидат SPDX (кл.) ★ / загр. Коммит Что даёт MOffice Стр. Риски / что пишем Эк.
Polars MIT (1) ★39,9k / 15,2M 2026-10-02 шаги «потоков данных» как LazyFrame (фильтр, join, union, pivot/unpivot, group_by), многопоточный CSV/Parquet/JSON для «большого режима» adopt (Sheets 1.6) +25–40 МБ к бинарнику; API меняется 2–3
arrow / parquet Apache-2.0 (1) ★3,6k / 84M 2026-09-29 Parquet/Arrow R/W (§5.22 sheets.md), ленивые чанки ChunkSource::Lazy adopt — 0,5
DuckDB + duckdb-rs MIT (1) ★41,7k / 4,4M 2026-09-30 SQL над Parquet/CSV, связанные «аналитические» таблицы Base adopt (опционально, плагин) C++ около 20–30 МБ; не дублировать Polars в ядре 0,5
DataFusion Apache-2.0 (1) ★9,4k / 28M 2026-09-29 SQL-движок на Rust ref / резерв тяжёлый; выбрать что-то одно: DuckDB или DataFusion —
csv Unlicense/MIT (0) ★2,0k / 258M 2026-08-04 RFC 4180, потоковый разбор adopt — 0,3
encoding_rs + chardetng (Apache OR MIT) AND BSD-3; Apache OR MIT (1) 554M; 14M 2026-09 / 03 кодировки WHATWG (cp1251, KOI8-R, IBM866) + детектор Firefox adopt заменяет свою «статистику байтов» из §5.21 sheets.md 0,5
HiGHS + highs MIT (1) ★1,9k / 1,1M 2026-09-30 LP/MIP: симплекс, IPM, ветви и отсечения; двойственные цены и диапазоны устойчивости adopt сборка C++ (cmake) 1,5–2
good_lp (проверено 2026-10-04) MIT (1) ★461 / 4,2M 2026-09-03 моделирование LP поверх HiGHS adopt с default-features = false по умолчанию тянет coin_cbc (EPL-2.0) 0,3
Clarabel Apache-2.0 (1) ★613 / 2,1M 2026-04-13 QP и конические задачи (выпуклый GRG-режим) adopt — 0,3
argmin MIT OR Apache-2.0 (1) ★1,3k / 5,2M 2025-11-07 L-BFGS, Нелдер–Мид, линейный поиск (GRG, FORECAST.ETS) adopt GRG с активными ограничениями и DE пишем сами 0,5
microlp / minilp Apache-2.0 (1) 1,5M / архив 2026-07 / 2020 чистый Rust LP для WASM-сборки adopt (wasm) слабее HiGHS —
statrs, nalgebra MIT; Apache-2.0 (1) 41M; 93M 2026-09 / 06 распределения (IronCalc уже использует statrs), QR/LU для LINEST/MINVERSE adopt — (в п. 1)
statsmodels (проверено 2026-10-04) BSD-3-Clause (1) ★11,7k 2026-10-03 Holt–Winters AAA — референс для FORECAST.ETS* ref / port алгоритма совпадение с Excel не гарантировано: Microsoft не публикует детали 0,5
jiff, chrono Unlicense OR MIT (0); MIT/Apache (1) 211M; 850M 2026-09 часовые пояса и календарная арифметика (Mail, NOW) adopt сериалы 1900/1904 и «ошибка 1900» — своя тонкая логика (есть в IronCalc) —
rust_decimal MIT (1) ★1,3k / 153M 2026-09-24 DECIMAL/MONEY/NUMERIC в Base и коннекторах adopt для Sheets не нужен (f64 + Ryū) —

2.7 MOffice Base

Кандидат SPDX (кл.) ★ / загр. Коммит Что даёт Стр. Риски / что пишем Эк.
SQLite + rusqlite blessing / PD (0); MIT (1) ★10,6k; 117M 2026-10-01 / 09-25 .mbx, хранилища Mail/Notes/Hub adopt (bundled) — (в базе)
SQLCipher Community (LICENSE.md проверен 2026-10-04) BSD-3-Clause (1) ★7,3k 2026-09-15 шифрование .mbx (AES-256, PBKDF2-HMAC-SHA512) adopt через rusqlite bundled-sqlcipher криптопровайдер: OpenSSL 3 (Apache-2.0) или CommonCrypto; не NSS (MPL) 0,5
sqlparser-rs Apache-2.0 (1) ★3,5k / 81M 2026-09-26 AST для диалектов SQLite/PG/MySQL/MsSql/Generic; QBE ↔︎ SQL, перевод Jet-SQL, разбор HSQLDB-скриптов .odb adopt комментарии и форматирование не сохраняются — храним исходный текст уже в плане (2–3 против «с нуля»)
tokio-postgres, mysql_async, tiberius, odbc-api MIT OR Apache / MIT (1) 72M; 7,8M; 5,3M; 1,7M 2026-06…09 нативные коннекторы PG, MySQL, MS SQL (TDS) и ODBC adopt за трейтом DbBackend ODBC на Linux/macOS загружает системный unixODBC (LGPL) — не поставлять уже в плане
sqlx MIT OR Apache (1) ★17,5k / 157M — единый async-API (PG/MySQL/SQLite) не брать в Base MS SQL удалён; два стека драйверов не держим —
FastReport Open Source (проверено 2026-10-04) MIT (1) ★3,1k 2026-09-11 эталон движка отчётов с полосами: группы, KeepTogether, CanGrow/CanShrink, двухпроходный «стр. N из M» ref / port алгоритма C#; раскладку и печать делаем через MOffice Print 0,5–1
JasperReports; BIRT LGPL-3.0; EPL-2.0 (2) ★1,4k; ★0,5k 2026-09 — только ref по документации заменены FastReport —
dbeaver, Baserow Apache-2.0; MIT (1) ★51,9k; ★2,2k 2026 конструктор запросов и ER-схема; формульные поля ref — —
NocoDB собственная с 2026-01-29 (3) ★65k — — avoid — —

3. Глубокие разборы

3.1 IronCalc как основа meridian-calc

Клон oss-src/ironcalc_IronCalc — коммит 9b1ae3f от 2026-10-02, workspace base, xlsx, bindings/{wasm,python,nodejs}. Зависимости base: serde, ryu, chrono(+tz), bitcode, csv, statrs, rand, regex — все класса 1.

Структура и объём (строк Rust, без тестов): base/src/functions — 35,3 тыс. (по категориям, functions/mod.rs — enum Function на 496 вариантов и диспетчер evaluate_function); expressions — 7,9 тыс. (лексер lexer/mod.rs в режимах A1 и R1C1, lexer/structured_references.rs, парсер parser/mod.rs — AST Node, parser/static_analysis.rs — 2,2 тыс., stringify.rs с to_rc_format и to_localized_string, move_formula.rs); formatter — 2,3 тыс.; user_model (undo, автозаполнение, буфер обмена) — 8,7 тыс.; model.rs — 3,9 тыс.; evaluation.rs — 1,1 тыс.; xlsx/src/import — 4,8 тыс., export — 3,8 тыс. Тесты: 288 файлов, 52 тыс. строк, 2 768 #[test], плюс 211 эталонных xlsx в xlsx/tests/calc_tests/<КАТЕГОРИЯ>/ (значения, вычисленные Excel).

Как это устроено и что из этого следует для нас.

Аспект IronCalc (файл) MOffice (sheets.md) Решение
Хранение ячеек sheet_data.rs: чанки по 1 024 строки, строка — отсортированный Vec<(col, Cell)> чанки 256×256, разреженные или плотные (§4.2) заменить на meridian-grid::CellStore; функции читают через трейт CellSource
Ячейка types.rs:367 enum Cell { Number, SharedString, CellFormula, ArrayFormula{r,kind}, SpillCell{a}, … } + s: i32 CellSlot { Value, StyleId, ExtraId } (§4.3) соответствие 1:1; SpillCell → Extra::SpillChild
Формулы shared_formulas: Vec<String> в R1C1 на лист + parsed_formulas: Vec<Vec<(Arc<Node>, StaticResult)>> (model.rs:199) общие формулы с base (§4.6) идея совпадает. FormulaStore хранит Arc<Node>; байткод — после бенчмарков
Пересчёт evaluation.rs:486 evaluate(): полный рекурсивный проход по всей книге, рестарты прохода для spill; графа зависимостей, инкрементальности и потоков нет (rayon не используется) граф + инкрементальный пересчёт + rayon по компонентам (§5.4–5.5) граф и планировщик пишем свои (референс — formualizer); из IronCalc берём вычисление одной формулы
Состояние вычисления variable_stack, lambdas, evaluation лежат в Model (&mut self) параллельные компоненты вынести в EvalFrame на поток; функции переводятся с &mut Model на EvalContext (механическая замена в 35 тыс. строк)
Spill порядок якорей + рестарты; model.rs:1224 spill_dynamic_array, functions/spill_functions.rs регистрация «пишущей» формулы в графе (§5.6) логику блокеров и #SPILL! берём, порядок даёт наш граф
Синтаксис A1 и R1C1, структурированные ссылки, @, A1#, LAMBDA-вызовы LAMBDA(..)(..); нет 3D-ссылок Лист1:Лист3!A1, внешних [Книга]Лист!A1, объединения , и пересечения «пробел» (token.rs:219 — таких токенов нет) всё P0 (§2.4) дописать: ≈2–3 тыс. строк, 1–1,5 чел.-мес.
Локали имена функций: en/de/fr/es/it (generate_language/src/languages.json); числовые локали: en, en-GB, de, es, fr, it (generate_locale/locales.json) ru и en — P0, ещё 16 языков — P1 JSON → locale/*.toml; русские имена 518 функций — наша таблица
Числовые форматы formatter/ (упрощённый, автор сам пишет в комментарии, что все правила Excel «практически невозможно» реализовать) §5.10 заменить портом SSF (§3.3)
xlsx импорт: стили, условное форматирование (0,9 тыс.), таблицы, комментарии (только чтение), гиперссылки, объединения, закрепление, имена, metadata dynamic arrays; нет проверки данных, диаграмм, изображений, сводных, защиты, спарклайнов, VBA, threadedComments, round-trip неизвестных частей полный round-trip (§7 sheets.md) кодек codec-ooxml/sml пишем свой; из IronCalc берём модули стилей и условного форматирования

Сравнение функций (скрипт fncov.py лежит в scratchpad сессии и в репозиторий не кладётся: он разбирает таблицы §5.23 sheets.md и сопоставляет их с languages.json IronCalc, function-map.ts Univer без закомментированных заглушек, экспортами src/*.js formulajs и fn name() в builtins formualizer). Каталог MOffice: 518 имён = P0 331 (317 + 14 алиасов) + P1 171 (147 + 24) + P2 16. Все 496 функций IronCalc входят в каталог; 4 из них — FORECAST.ETS, .CONFINT, .SEASONALITY, .STAT — заглушки #N/IMPL! (functions/statistical/forecast.rs:85).

Категория P0: всего / IronCalc P1: всего / IronCalc P2: всего / IronCalc Недостаёт; где взять (U — Univer, F — formualizer, J — formulajs, «—» — нигде)
Математические 57 / 56 24 / 24 — AGGREGATE (U, F, J)
Статистические 63 / 63 48 / 44 — FORECAST.ETS* ×4 (—; алгоритм по statsmodels)
Совместимость (алиасы) 14 / 14 24 / 24 — —
Текстовые 33 / 33 15 / 11 2 / 0 BAHTTEXT (U), DBCS (U), JIS (—), PHONETIC (—); TRANSLATE и DETECTLANGUAGE — через Assist
Логические, LAMBDA 20 / 20 — — —
Дата и время 25 / 25 — — —
Ссылки и поиск 35 / 34 5 / 2 1 / 0 GETPIVOTDATA (—, нужен наш PivotRender); IMAGE (U), GROUPBY (U, F), PIVOTBY (F); RTD (—)
Финансовые 27 / 27 24 / 24 4 / 4 —
Инженерные 24 / 24 30 / 30 — —
Информационные, БД, веб 33 / 33 1 / 0 9 / 0 FILTERXML (U); WEBSERVICE, EUROCONVERT (заглушки у Univer), CUBE* ×7 (—, значения из кэша файла)
Итого 331 / 329 (99,4 %) 171 / 159 (93,0 %) 16 / 4 (25 %) 492 / 518 = 95,0 %; с Univer и formualizer — 499 (96,3 %); остаются 19 своих (P0 — 1, P1 — 6, P2 — 12)

Для сравнения покрытие каталога другими движками: formualizer — 428, Univer — 493, formulajs — 403. Оговорка о качестве: «есть в IronCalc» ≠ «полностью как в Excel». В functions/ 33 места возвращают #N/IMPL! для частных случаев. 18 из них — «Arrays not supported yet»: массивы в аргументах AND/OR, COUNTIF-семейства, D-функций, SUBTOTAL, текстовых и дат-функций. Остальные — LAMBDA в аргументах, неявное пересечение в текстовых функциях и частичные INFO, CELL, SHEETS (functions/information/mod.rs:381–496). Закрыть этот список — ≈1 чел.-мес.

Многопоточность и производительность. У IronCalc их нет: однопоточный полный пересчёт. Для цели R1 из roadmap (1 млн формул ≤ 2 с, пересчёт после правки — мгновенный) нужен свой граф. Для сравнения: formualizer заявляет 1 млн формул за 0,38 с и 52 мс на пересчёт после правки одной ячейки (README, проверено 2026-10-04). Его engine/ даёт референс класса 1: interval_tree.rs — диапазонные слушатели, csr_edges.rs/delta_edges.rs — рёбра графа, scheduler.rs/topo/ — порядок, lookup_index_cache.rs — хэш-индекс для VLOOKUP/MATCH (§5.24 sheets.md).

Стратегия fork → kernel/crates/meridian-calc. (1) Снимок 9b1ae3f в ветку upstream/ironcalc; из двойной лицензии выбираем MIT; копирайт «Nicolás Hatcher и авторы IronCalc» — в NOTICE и в заголовках файлов. (2) I05, 3 недели: выделить parse/ и functions/, ввести трейты CellSource и EvalContext, прогнать 2 768 тестов и 211 xlsx на адаптере. (3) I05–I06: граф §5.4 и планировщик §5.5 с референсом formualizer. (4) I06–I07: 3D-ссылки, объединение, пересечение, внешние ссылки; ru-локаль; AGGREGATE (порт formualizer-eval/src/builtins/math/aggregate.rs); массивы в аргументах. (5) I07–I08: GROUPBY и PIVOTBY (builtins/lookup/dynamic.rs), IMAGE, FILTERXML, BAHTTEXT, DBCS (Univer), FORECAST.ETS* (statsmodels), GETPIVOTDATA (после сводных). (6) Раз в квартал переносить исправления из апстрима (≈0,25 чел.-мес.); для этого раскладка functions/ остаётся близкой к оригиналу.

Альтернатива — formualizer как движок целиком. Плюсы: граф и потоки уже есть. Минусы: покрытие каталога 428 против 492, хранение по столбцам Arrow вместо наших чанков 256×256, движок 0.10 переписан в 2026 году, ★187. Рекомендация — спайк на 2 недели в I05: прогнать 211 xlsx IronCalc и бенчмарк «1 млн формул» на обоих; решение зафиксировать в 03-architecture.md.

Экономия. С нуля 492 функции — это 28–35 чел.-мес. (1,2–1,5 чел.-дня на функцию с тестами и сверкой с Excel), парсер с локалями — 3–4, тесты — 6–8; всего 35–45. Против базиса E2.2 (≈ 21) остаётся 8–10: адаптер 1,5; граф и пересчёт 3–4; синтаксис 1–1,5; 26 функций 1,5–2; массивы 1; ru 0,3. Экономия 11–13 чел.-мес., и цель «500 функций» сдвигается с I08 на I06.

3.2 Источники недостающих функций: formulajs и Univer

Главный результат сравнения: портировать из JS/TS почти нечего. Из 26 функций, которых нет у IronCalc, Univer даёт 6, formualizer (Rust) — 3, formulajs — только AGGREGATE, которая есть и у двух других.

Univer engine-formula (Apache-2.0, oss-src/dream-num_univer/packages/engine-formula, коммит 2026-10-02):

formulajs (MIT, oss-src/formulajs_formulajs, v4.6.1, коммит 2026-10-01): src/*.js — 12,3 тыс. строк, 437 имён (403 из каталога), тесты test/*.js — 3 084 проверки, зависимости jstat (MIT) и bessel (лицензия не проверена). Уникальных для нас функций нет. Семантика JS: диапазоны — это массивы, пустые ячейки и текст в диапазонах приводятся не как в Excel. Поэтому ожидания из тестов прогоняем как третий оракул с фильтром: расхождение с IronCalc → разбор вручную, а не «истина».

Поправка в component-map.md. Было: «formulajs (411), Univer (502) — port — полный каталог». Нужно: «formualizer (AGGREGATE, GROUPBY, PIVOTBY) + Univer (IMAGE, FILTERXML, BAHTTEXT, DBCS) — port 7 функций; Univer + formulajs — тест-оракулы (≈8,6 тыс. проверок)». Экономия ≈1,5 чел.-мес.: 0,5 — функции, 1 — эталоны для стенда формул E2.6.

3.3 Числовые форматы: SheetJS SSF → meridian-numfmt

oss-src/SheetJS_ssf: Apache-2.0, последний коммит 2023-02-22 — репозиторий заморожен, развитие идёт в монорепо SheetJS (не проверено). Собранный ssf.js — 966 строк; исходники лежат в bits/*.js (1 146 строк). Главная ценность — эталоны, снятые с Excel: test/valid.tsv (442 кода), general.json (516), implied.json (756 — встроенные id), fraction.json (121), oddities.json (180), is_date.json (447), exp.tsv (46), dates.tsv (≈296 тыс. строк), times.tsv и cal.tsv (по 1 048 576 строк). Всего ≈2,4 млн проверок, 186 МБ — они лежат в тестовом репозитории, не в продукте.

Шаг порта Источник (bits/) Модуль meridian-numfmt Строк Rust Дней
Лексер, секции ;, условия [<100], цвета, [$-LCID] 80_split, 82_eval (лексер), 88_cond lexer.rs, section.rs 450 4
Компиляция в инструкции (грамматика §5.10.1 sheets.md) 82_eval compile.rs 400 4
Числа: группы, масштаб ,, %, E±, выравнивание ?, дроби (цепные дроби) 56_commaify…69_numfoot, 30_frac number.rs, fraction.rs 600 6
Даты и время: сериал → части, «ошибка 1900», 1904, [h], доли секунды, AM/PM, e/b, хиджра, тайские цифры 35_datecode, 50_date, 45_hijri, 49_thaidigits datetime.rs 450 4
«Общий» с подбором под ширину столбца (§5.10.4) 40_general + своё general.rs 250 3
Встроенные форматы id 0–49 и локальные id 50–81 25_table, 26_defaults builtin.rs 200 1
Локализация: разделители, месяцы и дни из ICU4X, [$₽-419], LCID → локаль у SSF только en-US — пишем сами locale.rs 300 4
Раннер эталонов (вне продукта) test/* tests/ssf_corpus.rs 300 3

Итого ≈3 тыс. строк и ≈29 рабочих дней, то есть 1,3–1,5 чел.-мес. С нуля, вместе со сбором эталонов, — 2,5–3. Экономия 1–1,5 чел.-мес. Сами дописываем то, чего в SSF нет: *x (заполнитель) и _x (отступ шириной символа) возвращаются как fill и pad в DisplayString, ширину считает рендер по метрике шрифта; [ColorN] — палитра из 56 цветов; японские эры g/gg/ggg (P2). meridian-numfmt заменяет formatter/ IronCalc и становится единым механизмом для отображения, TEXT(), экспорта CSV «как отображено», Base и Forms. В NOTICE: «SheetJS SSF, © SheetJS LLC, Apache-2.0»; в файлах — заголовок «основано на SheetJS SSF».

3.4 Бинарные форматы: POI, calamine, cfb, шифрование, RTF

Apache POI (Apache-2.0, ★2,3k, коммит 12c3688 от 2026-10-03; частичный клон для подсчёта — scratchpad/fmt-src/apache_poi). Объём модулей Java приведён как «файлов / строк / строк кода без комментариев».

Модуль POI (путь) Формат Java Что портируем → куда Rust, тыс. строк Порт / с нуля, чел.-мес.
poi/…/hssf/record (+ aggregates, cf, chart, pivottable) xls BIFF8 248 / 45,2k / 28,8k ≈250 записей: SST, XF, FORMULA, SHRFMLA, ARRAY, CF, DV, имена, графика → codec-msbinary/xls 18 4–5 / 8–10
poi/…/hssf/usermodel xls 65 / 22,9k / 14,2k не портируем (модель своя); логику сборки — выборочно — —
poi/…/ss/formula/ptg формулы xls и xlsb 68 / 6,0k / 4,3k кодирование и декодирование PTG → codec-msbinary/ptg (общий для xlsb) 2,5 0,7 / 1,5
poi/…/ddf OfficeArt (Escher) 38 / 6,8k / 4,2k фигуры и BLIP для xls, doc, ppt, pub → codec-msbinary/officeart 3 0,8 / 1,5
poi/…/hpsf SummaryInformation 46 / 9,2k / 4,4k свойства документа → codec-msbinary/props 2,5 0,5 / 1
poi-scratchpad/…/hwpf doc 199 / 54,4k / 36,7k model/ (FIB, TextPieceTable, CHP/PAP/SEP-таблицы, StyleSheet, ListTables, FieldsTables, NotesTables, PicturesTable), sprm/ → codec-msbinary/doc 15–18 4–5 / 8–10
poi-scratchpad/…/hslf ppt 169 / 34,7k / 21,3k record/ (≈100 атомов и контейнеров), model/textproperties → codec-msbinary/ppt 12–14 3–4 / 6–7
poi-scratchpad/…/hdgf, poi-ooxml/…/xdgf vsd; vsdx 27 / 2,7k; 56 / 6,6k распаковка VisioDocument, чанки; фигуры и наследование мастеров vsdx → codec-vector 4 1,1 / 3
poi-scratchpad/…/hpbf pub 14 / 1,6k / 1,0k текст QuillContents, EscherStm → codec-publisher 0,7 0,2 / 0,5
poi/…/poifs, poifs/crypt CFB; шифрование 115 / 18,7k; 50 / 7,7k не портируем: крейт cfb + offcrypto (ниже) — —
poi-scratchpad/…/hsmf, hwmf, hemf msg; wmf, emf 25 / 5,7k; 68 / 23,7k msg — референс; wmf/emf — кандидат для codec-vector (вне этой области) — —

Итого порт ≈ 15–17 чел.-мес. против 30–37 по спецификациям [MS-DOC], [MS-XLS], [MS-PPT] «с нуля». Экономия против базиса E1.4, E2.4 и E3.4 — 9–12 чел.-мес.: doc 3–4, xls 3–4, ppt 2–3, vsd/vsdx 1–1,5. Порядок: фаза 1 — DDF, HPSF, HWPF (doc R — P0); фаза 2 — записи HSSF и PTG (xls R — P0, W — P1; xlsb R через тот же PTG); фаза 3 — HSLF (ppt R), HDGF/XDGF, HPBF. Приём порта: не копировать ООП-иерархию POI, а описать записи декларативно (структуры плюс таблица «sid → декодер»). Запись doc и ppt у POI слабая, поэтому писатели делаем свои (doc W — P1, ppt W — P2). Вторым референсом поведения служат фильтры Apache OpenOffice (Apache-2.0): ww8, sc/source/filter/excel, sd/source/filter/ppt — пути не проверены.

calamine (MIT, v0.36.1, коммит 2026-09-02, 17,3 тыс. строк, scratchpad/fmt-src/tafia_calamine): src/xls.rs (2,0k), src/xlsb/ (1,3k), src/xlsx/ (5,2k), src/ods.rs (0,8k), src/vba.rs (467 строк: распаковка [MS-OVBA] и извлечение модулей), src/formats.rs (дата ли это по формату). Читает значения, формулы (PTG → текст для xls и xlsb), объединения, имена, VBA и изображения; стилей, условного форматирования, проверки данных и диаграмм нет. Стратегия: adopt для лёгких сценариев только-чтения (импорт в Base, источник «Excel» в потоках данных, предпросмотр в Hub, Forms) и fork vba.rs в meridian-script/vba, чтобы транслятор VBA получал исходники модулей из xlsm, xls, doc и accdb. Кодек Sheets — свой. Экономия 1–2 чел.-мес.

CFB: adopt крейта cfb (MIT, 68 млн загрузок, чтение и запись v3/v4). Шифрование — модуль codec-core/offcrypto:

RTF: своя реализация по спецификации Microsoft RTF 1.9.1. Ридер ≈4–5 тыс. строк: группы, ≈1 500 управляющих слов, \trowd, \listtable, \field, \pict, \uN, кодовые страницы через encoding_rs. Писатель — 2–3 тыс. Всего 3–3,5 чел.-мес. Референсы класса 1: токенизатор rtf-parser (MIT) и RTF-фильтры Apache OpenOffice (svtools/source/svrtf, sw/source/filter/rtf; не проверено). Классы 2–3 не трогаем: pandoc (GPL), writerfilter LibreOffice (MPL). Сжатый RTF (LZFu) из PST и MSG — свой, ≈200 строк по [MS-OXRTFCP].

3.5 Access: jackcess → codec-access

jackcess (Apache-2.0, ★120, коммит 2026-09-13, oss-src/jahlborn_jackcess): 194 файла в src/main (≈56 тыс. строк) и 45 тестовых классов; 86 тестовых баз .mdb/.accdb (Apache-2.0) — их берём в корпус. Карта кода src/main/java/com/healthmarketscience/jackcess/:

jetdb (MIT OR Apache-2.0, crates.io 0.3.3, ★13, коммит 2026-10-03; проверено 2026-10-04 по README) — то, что base.md §6.2 собирался писать сам. Это чистый Rust, Access 97 (Jet3) … 2019 (ACE17): каталог, схема (столбцы, индексы, связи), строки, генерация DDL для SQLite/PG/MySQL, восстановление SQL сохранённых запросов, исходники VBA, макросы в виде текста SaveAsText, LvProp, расшифровка (RC4 Jet, Agile, RC4 CryptoAPI, Standard AES), сборка под wasm32. Ограничения: только чтение, полный скан без индексов, все строки грузятся в память. Тестовые базы взяты из jackcess. Юридическая оговорка: автор благодарит mdbtools за HACKING.md — это документация формата, не код. Факты о формате не охраняются, но перед fork нужна короткая проверка, что кода mdbtools в jetdb нет; затем — запись в реестр.

План codec-access:

  1. Fork jetdb в kernel/crates/codecs/codec-access, исправления по возможности отдаём в апстрим. 0,3 чел.-мес.
  2. Доработки: потоковый итератор строк вместо Vec, кодовая страница Jet3 из заголовка (cp1251 для русских баз через encoding_rs — проверить, есть ли она в jetdb), сопоставление типов Access → SQLite (§4.3 base.md), пакетный импорт в .mbx транзакциями по 10 тыс. строк. 0,5 чел.-мес.
  3. Порт из jackcess по необходимости: impl/complex/* → вложения в дочерние таблицы, многозначные поля в JSON (0,3); impl/query/* — сверка с восстановлением SQL у jetdb (0,2).
  4. impl/expr/* не портируем. Список функций Default*Functions служит спецификацией для слоя совместимости «выражения Access» в meridian-calc (IIf, Nz, Format, DateDiff, DLookup…), как предлагает вопрос 10.2 base.md. 0,5 чел.-мес.
  5. CI: сверка jetdb ↔︎ jackcess (Java как инструмент тестов, не в продукте) на 86 базах + 100 реальных из §9 base.md.

Итого 1,8–2 чел.-мес. вместо 4–5. Экономия 3–4 чел.-мес. (E5.6). Если jetdb не пройдёт проверку — порт чтения jackcess (≈12–15 тыс. строк Java → 9–11 тыс. Rust, 2,5–3,5 чел.-мес.), экономия 1,5–2. mdbtools (GPL-2.0) и обёртку mdbsql не используем ни как код, ни как «референс»: ссылки на mdbtools в base.md (§6.2, §9) и 04-file-formats.md (§4.10) нужно убрать (§7).

3.6 OneNote, PST, MSG

OneNote — onenote.rs / onenote_parser (MPL-2.0, класс 2, v2.0.0, коммит 2026-08-06, oss-src/msiemens_onenote.rs). Объём crates/parser — 18,6 тыс. строк Rust:

Тестов почти нет (276 строк); записи нет. Чернила и формулы разобраны реверсом — в спецификации их нет.

Своя реализация по [MS-ONESTORE] и [MS-ONE] (Open Specification Promise). Хранилище ревизий (заголовок, FileNodeList, ≈40 типов FileNode, манифесты ObjectSpace и Revision, ExtendedGUID и CompactID, журнал транзакций, FileDataStore) — 3–4 тыс. строк. Объекты jcid* (Page, Outline, OutlineElement, RichText с TextRunFormatting, Image, Table, EmbeddedFile) — 5–6 тыс. Отображение в n:page/n:outline/t:p/tb:table — 1–2 тыс. FSSHTTPB для OneDrive — 2–3 тыс. (P2). Итого 11–15 тыс. строк, 4–6 чел.-мес., плюс 1 на чернила и формулы реверсом. Референс класса 1 — pyOneNote (Apache-2.0, ★153, последний коммит 2024-07-11, проверено 2026-10-04; полнота не проверена). Варианты решения для владельца — §4.

PST — outlook-pst (MIT; crates.io 1.2.0, 175 тыс. загрузок; github microsoft/outlook-pst-rs, ★36, коммит 2026-09-30; проверено 2026-10-04). README называет его «clean room»-реализацией [MS-PST] от Microsoft, совместимой с mspst32.dll и переносимой между ОС. Adopt. codec-mail/pst — тонкий адаптер по §4.9 04-file-formats.md: папки → mm:folder; сообщения → .eml (MIME собирается из MAPI-свойств, RTF → HTML с де-инкапсуляцией [MS-OXRTFEX] и распаковкой LZFu); встречи → VEVENT (AppointmentRecurrencePattern → RRULE через rust-rrule); контакты → vCard. Это 1–1,5 чел.-мес. вместо своих NDB/LTP/Messaging (≈15–20 тыс. строк, 5–6 чел.-мес.). Экономия 4–5. Не проверено: OST, запись, потоковое чтение 50-гигабайтных файлов — первая задача спайка в I17. Альтернативы не нужны: libpff (LGPL-3), java-libpst (Apache/LGPL, заброшен с 2022), XstReader (MS-PL, 2021).

MSG ([MS-OXMSG]: CFB, потоки __substg1.0_*, __properties_version1.0): msg_parser (MIT, 303 тыс. загрузок, ★10) подходит для быстрого старта; целевой вариант — своя реализация ≈1 тыс. строк на крейте cfb с общим слоем MAPI-свойств вместе с PST. Референс — POI HSMF. Экономия ≈0,5.

3.7 iWork, Visio, Publisher

iWork (IWA, iWork 2013 и новее). Устройство: ZIP или папка-пакет с Index/*.iwa. Каждый .iwa — кадры snappy в варианте Apple (без CRC), внутри — varint-длина, TSP.ArchiveInfo и protobuf-сообщения объектов со ссылками по идентификаторам. Рядом лежат Data/* (медиа) и preview.jpg. Что есть класса 1:

keynote-parser без лицензии — не берём. libetonyek (MPL-2.0) нужен был бы только ради старых XML-форматов iWork '09 — их предлагаем не поддерживать.

План codec-iwork: контейнер (snap + prost) — 1,5 тыс. строк; Numbers — таблицы, формулы TSCE → наш AST, стили — 4 тыс.; Pages — TSWP: текст, стили, списки, таблицы, изображения — 4–5 тыс.; Keynote — слайды, мастера, фигуры, текст, анимации в P2 — 4 тыс. Итого 13–15 тыс. строк, 5–6 чел.-мес. вместо 7–9 вслепую, экономия 2–3. Риск: схемы .proto машинно извлечены из приложений Apple. Это функциональное описание формата для совместимости, но нужно юридическое заключение в фазе 0 вместе с вопросом об OSP.

Visio. VSDX: спецификация [MS-VSDX] (OSP) плюс порт POI XDGF (poi-ooxml/…/xdgf: 56 файлов, 4,5 тыс. строк кода — страницы, мастера, наследование ячеек ShapeSheet, геометрия MoveTo/LineTo/ArcTo/NURBSTo/PolylineTo…, текст). Порт ≈3 тыс. строк Rust в codec-ooxml/vsdx — 0,8 чел.-мес. вместо 2; запись vsdx — своя (≈2 чел.-мес.). VSD (бинарный) спецификации не имеет. POI HDGF (2,7 тыс. строк: распаковка HDGFLZW, потоки и чанки, таблица разбора chunks_parse_cmds.tbl) даёт структуру и текст. Ячейки ShapeSheet в VSD — те же, что в [MS-VSDX], поэтому остальное восстанавливаем «чистой комнатой» по парам файлов, сохранённых из Visio в VSD и VSDX, — 3–4 чел.-мес. Экономия 1–1,5. Фразу «R* через портирование подхода libvisio» в §4.4 04-file-formats.md заменить (libvisio — класс 2, §4).

Publisher. Спецификации нет. POI HPBF (1,6 тыс. строк: QuillContents — текст и гиперссылки, EscherStm — фигуры) за 0,2 чел.-мес. даёт R* «только текст»: поиск и индекс в Hub, импорт текста в Write. Полный R* (страницы, рамки, связанные фреймы, стили) — 3–4 чел.-мес. своими силами или libmspub (MPL-2.0) — решение владельца (§4). Рекомендация: в 1.x — только текст через HPBF; полный импорт решить в фазе 7 по запросам пользователей.

3.8 Base: SQLite, SQLCipher, sqlparser-rs, коннекторы, отчёты

Хранилище. SQLite (public domain, класс 0) через rusqlite (MIT, 0.40.2). SQLCipher Community — BSD-3-Clause, © Zetetic LLC (текст LICENSE.md проверен 2026-10-04), класс 1. Обязательство одно: уведомление в документации бинарного дистрибутива, то есть в окне «О программе». Формат SQLCipher 4 (AES-256-CBC, HMAC-SHA512, PBKDF2 на 256 000 итераций) совпадает с §2.6 base.md. Ответ на вопрос 10.4 base.md: статическая сборка через rusqlite bundled-sqlcipher-vendored-openssl (OpenSSL 3 — Apache-2.0) на Windows и Linux и CommonCrypto на macOS; провайдер NSS (MPL) не используем. Важно для архитектуры (не проверено в коде, по документации rusqlite): фичи bundled и bundled-sqlcipher собирают один и тот же libsqlite3-sys и не совмещаются в одном процессе. Поэтому весь пакет — Base, Mail, Notes, индекс Hub — переводим на сборку SQLCipher: без ключа она работает как обычный SQLite. Это нужно записать в 03-architecture.md.

sqlparser-rs (Apache-2.0, 0.63.0) — уже выбран в §5.2 base.md. Подтверждаем и уточняем, где он применяется: SQL → AST → QueryDesign, если запрос укладывается в подмножество QBE; QBE → SQL через AST с кавычками по диалекту; перевод Jet-SQL из MSysQueries — свой предпроцессор для #дат#, */? в LIKE и IIf, а скобки [Таблица].[Поле] разбирает диалект MsSql; разбор HSQLDB-скриптов из .odb — диалектом Generic. Ограничение: комментарии и форматирование теряются, поэтому исходный текст SQL храним всегда.

Коннекторы — adopt за трейтом DbBackend (§4.7 base.md):

sqlx не берём: был бы второй стек драйверов, а поддержку MS SQL из него убрали. DuckDB (MIT) — отдельный плагин «связанные таблицы Parquet/CSV и аналитические запросы»; в базовую установку его вместе с Polars не тянем.

Отчёты — свой банд-движок (§5.10 base.md). Референсы:

Экономия по Base против плана — 2–3 чел.-мес.: SQLite, sqlparser-rs и драйверы уже заложены в base.md; новое здесь — готовый SQLCipher, FastReport и Grist как референсы, DuckDB-плагин. jetdb (§3.5) считается отдельно.

4. Класс 2 — решения владельца

В колонке «Вариант A» — взять компонент по правилам его лицензии. В колонке «Вариант B» — замена классов 0–1 или своя работа.

Компонент Лицензия Зачем Вариант A (по правилам лицензии) Вариант B (класс 0–1 / своё) Рекомендация
onenote_parser (onenote.rs) MPL-2.0 импорт .one/.onepkg в Notes (фаза 5, P1, R*) крейт без правок, в процессе codec-host; в «О программе» — ссылка на исходники; правки — только апстримом. 0,5–1 чел.-мес. своя реализация по [MS-ONESTORE]/[MS-ONE] + pyOneNote (Apache). 4–6 чел.-мес. A — экономия 4–5
libvisio (+ librevenge) MPL-2.0 (librevenge — MPL/LGPL) .vsd R* в Draw C++-библиотека в codec-host без правок; тянет boost POI HDGF + «чистая комната» по [MS-VSDX]. 3–4 чел.-мес. B: объём умеренный, C++-стек нежелателен
libmspub MPL-2.0 .pub R* в Write/Draw как libvisio POI HPBF (только текст, 0,2) сейчас; полный импорт своими силами (3–4) в фазе 7 B (текст), полный импорт — решить в фазе 7
libetonyek MPL-2.0 Pages, Numbers, Keynote как libvisio numbers-parser + iWorkFileFormat + litchi (§3.7). 5–6 чел.-мес. B; iWork '09 не поддерживаем
libpff LGPL-3.0 PST/OST динамическая линковка outlook-pst (MIT) B — решение не нужно
epub-builder MPL-2.0 запись EPUB крейт без правок свой EPUB 3 R/W на zip + quick-xml (0,7) B
cssparser, selectors, lightningcss MPL-2.0 (не проверено) CSS при импорте HTML — simplecss (MIT/Apache, не проверено) + свой каскад B
good_lp, фича по умолчанию coin_cbc EPL-2.0 (CBC) Solver — default-features = false + HiGHS; запрет coin_cbc в deny.toml B
JasperReports; BIRT; Pentaho LGPL-3.0; EPL-2.0; LGPL-2.1 движок отчётов Base отдельный JVM-процесс — неприемлемо для десктопа свой движок + FastReport (MIT) как референс B
ixion, orcus MPL-2.0 формулы и фильтры — IronCalc, свои кодеки не нужны
unixODBC (или iODBC) LGPL-2.1 (не проверено) ODBC на Linux и macOS системная библиотека, загружаем динамически, не поставляем — A: запись в реестр, юридический риск минимален
XstReader MS-PL PST — outlook-pst не нужен. Предложение: внести MS-PL в класс 2 политики
libwpd (для .wpd) MPL-2.0/LGPL (не проверено) чтение WordPerfect в Write (P1) как libvisio своя реализация (≈3 чел.-мес.) отложить: спрос низкий

5. Запрещено (класс 3) и замены

Проект Лицензия Где возникал соблазн Замена
mdbtools (+ обёртка mdbsql) GPL-2.0 .mdb/.accdb; упомянут как референс в base.md §6.2 и §9 и в 04-file-formats.md §4.10 jetdb + jackcess (§3.5)
epub (epub-rs) GPL-3.0 (проверено 2026-10-04) чтение EPUB свой EPUB R/W
HyperFormula GPL-3.0 / коммерч. движок формул IronCalc (+ formualizer)
LibreOffice core, Gnumeric, Calligra, AbiWord GPL/LGPL (в tsv — класс 3) эталоны функций и фильтров doc/xls/ppt/rtf/vsd/pub поведение изучаем только как пользователи (ферма эталонных рендеров из §1.3 roadmap); код класса 1 — Apache OpenOffice
ONLYOFFICE (x2t, sdkjs) AGPL-3.0 конвертеры форматов POI, AOO, свои кодеки
EPPlus PolyForm-Noncommercial xlsx rust_xlsxwriter, umya-spreadsheet, ClosedXML
NocoDB собственная с 2026-01-29 «таблицы-БД» Baserow (MIT), Grist (Apache)
keynote-parser лицензии нет = все права защищены Keynote numbers-parser, iWorkFileFormat, litchi
antiword, catdoc, wvWare GPL (не проверено) извлечение текста из doc POI HWPF
pandoc GPL-2.0+ (не проверено) конвертеры md/rtf/epub/docx comrak, свои кодеки
R forecast GPL (не проверено) алгоритм ETS statsmodels (BSD-3)
LibreOffice или unoconv как встроенный конвертер MPL/LGPL/GPL «быстрый» импорт редких форматов не встраиваем; каждый формат — своим кодеком или в R*
Описания функций в Univer locale/function-list/*/ru-RU.ts формально Apache-2.0, но тексты похожи на справку Microsoft «Мастер функций» пишем свои описания (§3.2)

6. Что переносим кодом

Правило для всех строк: в заголовок каждого перенесённого файла — «основано на <проект> (), © авторы <проект>»; в NOTICE и в окно «О программе → Лицензии» — точный текст копирайта из LICENSE/NOTICE источника. Если у источника двойная лицензия «MIT OR Apache-2.0», выбираем MIT: у неё нет требования по NOTICE.

Источник (файл / модуль) Куда в MOffice Лицензия Атрибуция, NOTICE Способ
IronCalc base/src/expressions/{lexer,parser}/**, parser/static_analysis.rs kernel/crates/meridian-calc/src/{parse,analysis}/ MIT «IronCalc, © Nicolás Hatcher и авторы» fork
IronCalc base/src/functions/**, cast.rs, arithmetic.rs, calc_result.rs, implicit_intersection.rs, units.rs meridian-calc/src/functions/<категория>.rs MIT то же fork + переход на EvalContext
IronCalc model.rs (spill_dynamic_array, retire_own_spill_cells), functions/spill_functions.rs meridian-calc/src/spill.rs MIT то же fork частей
IronCalc generate_language/src/languages.json, generate_locale/locales.json meridian-calc/locale/*.toml (+ ru.toml) MIT то же преобразование данных
IronCalc base/src/test/**, xlsx/tests/calc_tests/**/*.xlsx meridian-calc/tests/, корпус MIT вне продукта копия
IronCalc xlsx/src/import/{styles,conditional_formatting,metadata,tables}.rs, export/{styles,conditional_formatting}.rs codecs/codec-ooxml/src/sml/ MIT то же fork частей
formualizer crates/formualizer-eval/src/engine/{interval_tree,csr_edges,delta_edges,lookup_index_cache,scheduler}.rs, topo/ meridian-calc/src/graph/ MIT «Formualizer, © авторы» port / ref (Rust → Rust)
formualizer src/builtins/math/aggregate.rs, src/builtins/lookup/dynamic.rs meridian-calc/src/functions/ MIT то же port
Univer packages/engine-formula/src/functions/{web/filterxml,lookup/image,text/bahttext,text/dbcs}/index.ts meridian-calc/src/functions/ Apache-2.0 «Univer, © 2023-present DreamNum Co., Ltd.» + Apache-2.0 port TS → Rust
Univer **/__tests__/index.spec.ts; formulajs test/*.js meridian-calc/tests/oracle/ Apache-2.0; MIT вне продукта конвертер
SheetJS SSF bits/*.js; test/* kernel/crates/meridian-numfmt/src/; корпус Apache-2.0 «SheetJS SSF, © SheetJS LLC» port
statsmodels, модуль Holt–Winters (путь не проверен) meridian-calc/src/functions/statistical/ets.rs BSD-3-Clause «© statsmodels developers» port алгоритма
Apache POI poi/…/{hssf/record,ss/formula/ptg,ddf,hpsf}/**, poi-scratchpad/…/{hwpf/model,hwpf/sprm,hslf/record,hslf/model/textproperties,hdgf,hpbf}/**, poi-ooxml/…/xdgf/** codecs/codec-msbinary/{xls,ptg,officeart,props,doc,ppt}, codec-vector/vsd, codec-ooxml/vsdx, codec-publisher Apache-2.0 NOTICE Apache POI («This product includes software developed by The Apache Software Foundation») + Apache-2.0 port
calamine src/vba.rs meridian-script/src/vba/extract.rs MIT «calamine, © Johann Tuffe» fork
msoffcrypto-tool method/{rc4,rc4_cryptoapi,xor_obfuscation}.py, format/{doc97,xls97,ppt97}.py codecs/codec-core/src/offcrypto/ MIT «msoffcrypto-tool, © nolze» port
jetdb (весь крейт) codecs/codec-access/ MIT «jetdb, © авторы» fork
jackcess impl/complex/**, impl/query/**; список impl/expr/Default*Functions.java codec-access/src/{complex,query}, meridian-calc/src/compat/access.rs Apache-2.0 NOTICE.txt jackcess + Apache-2.0 port; список функций — как спецификация
numbers-parser, .proto-схемы (путь не проверен) codecs/codec-iwork/protos/ MIT (+ юридическое заключение) «numbers-parser, © авторы» port данных
FastReport, движок полос (путь не проверен) meridian-base/src/report/engine.rs MIT «FastReport, © Fast Reports Inc.» port алгоритма
office-crypto, ms-offcrypto-writer, outlook-pst, cfb, calamine, rusqlite + SQLCipher, sqlparser, Polars, arrow/parquet, csv, encoding_rs, chardetng, HiGHS/highs, good_lp, Clarabel, argmin, statrs, nalgebra, rust_decimal, jiff зависимости Cargo.toml см. §2 SBOM (CycloneDX) → «О программе» автоматически adopt

7. Предложения в библию и план

  1. component-map.md.
    • «Sheets / недостающие функции» переписать: formualizer (3) и Univer (4) — port; Univer и formulajs — тест-оракулы (§3.2).
    • «Sheets / движок»: добавить formualizer как референс графа и спайк «IronCalc против formualizer» в I05.
    • «CFB и шифрование»: cfb + office-crypto + ms-offcrypto-writer (adopt) + порт msoffcrypto-tool для бинарных форматов.
    • Access → «jetdb fork + jackcess port частей». PST → «outlook-pst (Microsoft, MIT) adopt» вместо «своего по [MS-PST]».
    • Новые строки: iWork (numbers-parser, iWorkFileFormat — ref), Visio (POI XDGF/HDGF — port), Publisher (POI HPBF — port), отчёты Base (FastReport — ref), EPUB (свой; epub — GPL, epub-builder — MPL).
  2. base.md.
    • §6.2 вместо «референсы: mdbtools, Jackcess…» — «fork jetdb + jackcess; mdbtools (GPL) не используется».
    • §9 вместо «сверка с mdbtools/Jackcess» — «сверка jetdb ↔︎ jackcess».
    • Ответ на §10.4: единая SQLCipher-сборка SQLite на весь пакет, провайдер — OpenSSL 3 или CommonCrypto (§3.8).
  3. 04-file-formats.md.
    • §4.10: убрать «по подходу MDB Tools».
    • §4.4: VSD — «POI HDGF + [MS-VSDX], libvisio — класс 2».
    • §5.1: добавить outlook-pst, jetdb, office-crypto, ms-offcrypto-writer; для calamine — «adopt для R-сценариев + fork vba.rs».
    • §1.3, корпус, добавить: 211 xlsx и 2 768 тестов IronCalc, ≈2,4 млн эталонов SSF, 86 баз jackcess, тестовые файлы msoffcrypto-tool, ≈8,6 тыс. проверок Univer и formulajs.
  4. sheets.md.
    • §4.6: старт — интерпретатор AST (Arc<Node>, общие формулы) из IronCalc, байткод — после бенчмарков.
    • §5.10: meridian-numfmt — порт SSF, эталоны SSF прогоняются в CI.
    • §5.16: симплекс, ветви и границы и отчёты устойчивости — HiGHS через highs/good_lp без coin_cbc; GRG — argmin (L-BFGS) + свой слой активных ограничений; QP — Clarabel.
    • §5.21: csv + encoding_rs + chardetng вместо своей статистики байтов; Polars — для «большого режима» и потоков данных.
    • §5.23: у каждой функции указать источник (IronCalc / formualizer / Univer / своё); 19 своих функций — по списку §3.1.
    • Мастер функций: описания пишем сами.
  5. 08-roadmap.md, E2.2.
    • I05: fork IronCalc + адаптер, ≈490 функций (вместо «150 функций»); I06: граф, пересчёт, 500+ функций.
    • Высвобожденные 1–2 Rust FTE — на сводные таблицы и Chart; в I05 — двухнедельный спайк IronCalc против formualizer.
    • E1.4: порт HWPF в I03–I05.
    • E5.6: PST и accdb через outlook-pst и jetdb — эпик дешевле на 7–9 чел.-мес.; есть смысл поднять pst и accdb из P1 в P0 фазы 5.
  6. 12-license-policy.md.
    • MS-PL — в класс 2.
    • При двойной лицензии (например, Apache-2.0/LGPL у java-libpst) выбираем разрешительную.
    • Новый особый случай: тексты справки Microsoft внутри чужих проектов (описания функций Univer) не берём; машинно извлечённые схемы (.proto iWork) — только после юридического заключения.
  7. deny.toml (фаза 0).
    • Запретить epub (GPL), coin_cbc/coin-cbc-sys (EPL), cssparser/selectors/lightningcss (MPL).
    • onenote_parser — добавить в exceptions после решения владельца.
  8. 03-architecture.md.
    • «Один SQLite на процесс — сборка SQLCipher».
    • codec-host — место для изолированных компонентов класса 2, если владелец их одобрит.

8. Непроверенное

Ниже — то, что в этой сессии не проверено. Остальные факты либо есть в oss-verified.tsv, либо проверены 2026-10-04: по клонам, через API crates.io и GitHub или по тексту LICENSE.

Утверждение Что сделать
Возможности outlook-pst: OST, запись, потоковое чтение файлов на 50 ГБ, экспорт типов MAPI-свойств для общего с MSG слоя спайк в I17 на корпусе PST
Происхождение кода jetdb (автор ссылается на HACKING.md mdbtools) и поддержка кодовых страниц Jet3 (cp1251) короткий юридический и технический аудит перед fork
formualizer: число активных авторов, устойчивость API 0.10, совпадение функций с Excel спайк I05 (§3.1)
Качество импорта xlsx у IronCalc на реальном корпусе (3 000 файлов) прогон corpus-tool в I05
Происхождение русских описаний функций Univer (сверено по стилю ABS и ACOS и по ссылкам на support.microsoft.com) сравнение со справкой; до проверки — не брать
Наличие NOTICE у Univer; лицензия npm-пакета bessel (зависимость formulajs) проверить перед портом
Пути исходников: FastReport (FastReport.Base/Engine), statsmodels (tsa/holtwinters), numbers-parser (protos), RTF-фильтры Apache OpenOffice при старте соответствующих задач
Лицензии cssparser, selectors, lightningcss (MPL-2.0 по памяти), simplecss (MIT/Apache), unixODBC (LGPL-2.1), libwpd scripts/oss_verify.py
GPL у antiword, catdoc, wvWare, pandoc, R forecast scripts/oss_verify.py (влияет только на список «запрещено»)
Поддержка .numbers в SheetJS CE; актуальный апстрим SSF в монорепо SheetJS проверить git.sheetjs.com
Несовместимость фич bundled и bundled-sqlcipher у rusqlite в одном бинарнике проверка сборкой в фазе 0
Правовой статус машинно извлечённых .proto-схем iWork и интероперабельность по директиве ЕС 2009/24/EC юридическое заключение в фазе 0
Полнота pyOneNote и litchi как референсов при старте codec-onenote и codec-iwork
Лицензия jackcessencrypt (по README jetdb — Apache-2.0); репозитория jahlborn/jackcess-encrypt на GitHub нет не нужен, если шифрование закрывает jetdb

Дополнительных веб-запросов в этой сессии — около 45: API crates.io и GitHub, 4 README, LICENSE SQLCipher и 4 клона: POI (частичный), calamine, msoffcrypto-tool, formualizer. Это чуть выше лимита BRIEF (~40); последние запросы ушли на лицензионно значимые вопросы (good_lp, SQLCipher).