OxL Справочник OxL
РусскийEnglish

Приложение B. Что изменено ради согласованности

При переводе черновика в стандарт найдены и устранены противоречия. Таблица — для сверки со старыми обсуждениями.

БылоСталоПричина
data Dog { use Animal }embed Animaluse уже означает импорт
service Users @v2 {, атрибуты после имени@v(2) service Users { — атрибуты всегда перед объявлениемодин синтаксис атрибутов
resize @gpu в пайплайнеresize on gpu@ зарезервирован за атрибутами
2026-11-03T18:00 @ "Europe/Moscow"2026-11-03T18:00.in(tz"Europe/Moscow")та же причина; @ убран из символов пользовательских операторов
тернарный a > b ? a : bif a > b { a } else { b }конфликт с постфиксным ? и T?
поле email?: Emailemail: Email?один способ записать опционал
@auth(role: Admin) и политикитолько политики и сокращение @allow(…)два механизма для одного
@secret apiKey: strapiKey: secret<str>один механизм секретов
config<App>(), dynamic<Limits>()App.get(), Limits.get()config — ключевое слово
every(5m) -> sync()every(5m) { sync() }-> — только цепочки
select { rx => j -> process(j) }select { recv j from rx => process(j) }та же причина
.map @local(…) в cluster.shards.map(…) — всегда на владельцах шардовлишняя конструкция
stream<T> resumable@resumable rpc …атрибуты вместо модификаторов типа
-> u => (a(u), b(u)) как fan-outшаг-кортеж -> (a(it), b(it))лямбда, возвращающая кортеж, — обычное значение
@retry на любом rpcтолько с @idempotent или @readonlyповтор неидемпотентного вызова опасен
keep x для выноса из ареныарена — оптимизация реализации, без синтаксисасемантика не должна зависеть от аллокатора
traits и интерфейсытолько интерфейсы; служебные — @explicitструктурное соответствие + защита Drop/Copy от случайной реализации
неявное переопределение в embedopen fn в базе + override fnоднозначная диспетчеризация
теги полей по порядку объявленияoxl.schema.lock + @tag(n)вставка поля не ломает схему
retry в STMcheck(cond)конфликт с суффиксом цепочки retry
завершение main останавливает узелузел работает, пока что-то размещаетmain — задача запуска
cluster.leader блокируетрегистрирует задачу и возвращаетсявызывается из main на всех узлах
serves для топиковтопикам нужна только роль с journalтопики живут в хранилище
литералы Money.zeroMoney.zero()так было до ассоциированных констант; теперь допустимо и Money.ZERO (§4.5)
строгая обязательность политики для всех rpcвнешним принципалам — только явное; @internal; ошибка лишь для недоступного никому rpcвнутренние rpc разрешаются графом вызовов
таблицы во встроенном хранилище поверх LSMтаблицы builtin:// — SQLite на реплику шарда, Raft реплицирует наборы изменений строк; LSM — для KV и системных данныхсобственный исполнитель запросов (мини-СУБД) слишком сложен и рискован; SQLite даёт полный проверенный SQL
checkout в V.5 очищал корзину в фоне (~> Cart(uid).clear())checkout ждёт Cart(uid).removeOrdered(n); в фон уходит только ~> recs.learn(…)исправлено в примере V.5: фоновая очистка гонялась со следующим запросом пользователя (могла стереть позиции, добавленные после снимка); ~> годится для задач, не влияющих на состояние, от которого зависит ответ
inventory.reserve(ReserveReq{ items: snap.items }), payments.charge(ChargeReq{ … }), recs.learn(LearnReq{ … }) в V.5inventory.reserve(items: snap.items), payments.charge(user: …, amount: …), recs.learn(user: …, items: …)исправлено в примере V.5: при import proto сообщение-запрос раскрывается в параметры rpc (§16.3), конструировать его в вызове не нужно
в V.5 не было A/B-теста: §18.5 и критерий приёмки ссылаются на «search v2», которого нет в примерев V.5 добавлены Shop.search, search/search.oxl (варианты searchByName / searchByTag, выбор через ab.variant(..)), test ab "search v2" и записанный трафик traffic/search.oxlrec; ab.variant(..) из std.ab возвращает имя варианта запросаисправлено в примере V.5 (ответ заказчика 1a): пример показывает test ab и oxl ab на настоящем сервисе; способ узнать вариант из кода в §18.5 не был задан (ответ 8a: динамический Flag по split by)
в V.5 шаг после respond it.id получал p (фото целиком)шаг после respond it.id получает PhotoId: id => makeThumbs(id, THUMB_SIZES); владелец для PhotoReady — параметр пайплайна ownerисправлено в примере V.5: по тексту §10.6 следующему шагу передаётся значение respond
вопрос об асинхронных деструкторахсинхронный Drop + явный close() с defer + @must_closeнеявные точки приостановки, конфликт с отменой и потеря ошибок перевешивают удобство
строки let/assert на верхнем уровне файла в примерах (§4.2, V.3, приложение A); тело test ab как блокверхний уровень — только объявления; такие строки — фрагменты внутри функций и test; тело test ab — набор предложений variant/split/metric/guard/traffic (§0.2, §18.5)уточнено в редакции 1.0 (D-8052; DIV-001): парсер принимает на верхнем уровне только элементы
ProtocolError.Internal / .InvalidArgument как варианты перечисленияProtocolError — @error data { msg: str, code: i32 } с ассоциированными константами Internal (13), InvalidArgument (3), Unimplemented (12); обе записи работают (§6.5)уточнено в редакции 1.0 (D-8052; DIV-004; D-2901)
TxConflict — ошибка результата atomic(db)atomic(db) сохраняет тип тела; после исчерпания повторов — паника TxConflict (§11.2)поправка редакции 1.0 (D-8052; DIV-012): тип результата не меняется ради редкого случая под нагрузкой
[lint] показан только значением errorдопустимы error, warn/warning, off/allow (III.2)поправка редакции 1.0 (D-8056; DIV-042)
@owner ограничивает все чтения и записиусловие владельца добавляется к find/query/count/update/delete, не к load(…) и сырому SQL; чужие записи отвергаются (§13.4); условия set динамической конфигурации — только pureпоправка редакции 1.0 (D-8056; DIV-028, DIV-029)
политики debug и inspect названы без правилзаданы: роль Admin, debug/inspect или сертификат кластера с ролью (III.7, III.8)поправка редакции 1.0 (D-8056; DIV-041)
Format, Encoder, Decoder названы без сигнатур; decode(b, MyFormat)сигнатуры описаны (§9.5); декодирование собственным форматом — необязательная возможность impl-user-format-decodeпоправка редакции 1.0 (D-8053; DIV-007)
V.5: типы import proto общие для модулей, Client<Recs> в dep, reserve(items: …)реализация примера (examples/shop): типы .proto приватны для checkout, в тестах — алиасы OutOfStockError/DeclinedError; ReserveResp/ChargeResp имеют второе поле; Money на проводе — int64; ключ payments не передаётся (Connect без auth:)пример V.5 информативен; расхождения собраны в examples/shop/DEVIATIONS.md (#1; D-8057; DIV-047)
V.5: UserId(ctx.userId()?), caller.isUser(id) с UserIdCtx.userId() и isUser принимают str (JWT sub); callerId(ctx) разбирает его в UserId (§13.2, impl-principal-id)D-8057; DIV-049; D-2905
V.5: OrderEvents … sharded by .userIdтопик не шардирован (у элемента enum нет поля userId); watch фильтрует по владельцуD-8057; DIV-050 (DEVIATIONS #5)
V.5: photos с Image из imagekit, BlobStore, makeThumbs/moderate в photos/ml.oxlimagekit и BlobStore в 1.0 нет: образ — bytes, Blobs — локальный актор, makeThumbs/moderate — заглушки; THUMB_SIZES: List<u32>; Db.open(…)!D-8057; DIV-051 (DEVIATIONS #6, #10, #11); impl-stdlib-optional
V.5: тесты asUser, mock Inventory {…}, test sim, test integ with cluster(nodes: 3), asUser(uid) { a -> b }?asUser и TEST_ITEM — в tests/fixtures.oxl; ? в блоке asUser заменён на !; цепочку ждёт явный await (a -> b); в sim — 6 логических узлов (по роли, для saga — 2)D-8057; DIV-052 (DEVIATIONS #7; D-6114, D-6252)
V.5: поля pub(api) data без pubpub(api) нужен на каждом поле, которое использует другой модуль (поля приватны по умолчанию, §4.2)D-8057; DIV-053 (DEVIATIONS #9)
V.5: expose 443 tls(acme: …), seeds k8s(…)в тексте примера оставлено как есть; при приёмке переопределено флагами и переменными (--tls-cert/--tls-key, static[…], локальный JWKS, OXL_SHARDS=16, фиктивные gRPC-серверы)окружение: impl-acme, impl-seeds-k8s (D-8057; DIV-054)
atomic(db, cross_shard: true) разрешает несколько шардов ценой двухфазного коммитапараметр принимается с предупреждением cross-shard-tx, тело выполняется как обычная транзакция; выход за один шард — CrossShardTx во время работы (§11.2, impl-2pc)двухфазный коммит вне 1.0 (D-8064; D-7790)
@allow(…) — только краткая политика доступадобавлена форма @allow(lint: правило, reason: "…") — подавление правила анализатора на объявлении (III.4)идея C11 (D-8064; D-7830)
о dbg и о assert в профиле prod Стандарт молчалdbg вырезается в prod (ключ профиля dbg), assert выполняется во всех профилях (§2.2, §18.2)единообразие профилей (D-8064; D-7800)
исходящие вызовы несут пользователя и сервис без исключений (§13.2)вызовы внешних сервисов (S.connect) не несут x-oxl-principal/x-oxl-user (§13.2)утечка идентичности пользователя во внешние системы, дефект 1-й критичности (D-8066; D-8300)

Исходник: docs/spec/oxl-standard.md