arxohq/codegen — самостоятельная кодогенерация модели
Standalone repository: требуется явный валидированный LAW_CODEGEN_CORE_KIT;
соседний checkout law-dsl не используется.
Несовместимый выпуск 0.4.0 (этап R, 15.10.2026) принимает ровно 0.2.11 и
law.core.ir/0.7; прежние и будущие штампы отвергаются до планирования.
Реестр R.2 пересертифицирован: 1689 текущих векторов, 503 совпадения,
1186 закреплённых отказов/случаев вне профиля; py/ts/go, расхождений и
крахов нет. Приёмка 0.4.0 выполняется на установленном wheel через
ci/verify.py; vendor-пины и встроенный native lock обновляются вместе.
Push и теги выполняет владелец; локальная поставка — candidate. 51 errata квалифицирована портом, именованным отказом
или границей профиля; старые семантические пины из active registry удалены.
positions временно снят у ts, py, go: прямой вычислительный вход
отвечает POSITIONS_UNAVAILABLE до создания модели, перенос рангов — W6. Модель с norm_template либо нормативной головой
отказывает NORM_RANKS_UNAVAILABLE для любого вопроса. Цели больше не
объявляют norm; прежние эмиттеры лестницы и эффектов удалены.
Текущий сертифицированный профиль — только py, ts, go. Вторичные
цели и XLSX явно отказывают на admission:current до отдельного порта;
наличие их исторических исходников не означает поддержку текущего выпуска.
Одна числовая source-канарейка понижается текущим компилятором в Number:
проверяется NUMBER_UNAVAILABLE, пять остальных сохраняют mutation proof.
Публичный план — law-backend-plan/0.20: basePlanVersion выбирает
исполнительный формат 0.7–0.19, admission.reservedAssertionIds сохраняет
идентичности не-assertion узлов корня и зависимостей. Возможность
admission:current обязательна для текущей поставки py/ts/go. Transport case
с коллизией id получает LDC-E1382; typed temporal bounds проверяются до
вывода. Number даёт NUMBER_UNAVAILABLE до старой сверки типов слотов;
агрегаты в judgment-моделях — AGGREGATE_JUDGMENT_UNAVAILABLE (E-0357);
witness-bound backchain — JUDGMENT_WITNESS_UNAVAILABLE (E-0189).
Пределы текущей числовой арифметики не заменяются произвольной точностью:
границы i64/i128 дают NUMERIC_LIMIT_UNAVAILABLE; компактное ненулевое
десятичное расширение >4096 — DECIMAL_EXPANSION_UNAVAILABLE (E-0320).
Нулевые экстремальные exponent/scale нормализуются без огромных степеней
и циклов. Это явные границы среза, а не поддержка всего WP-13.
Быстрый цикл над свежим комплектом, без упаковки wheel:
python check_conformance.py --core-kit KIT --fixtures FIXTURES --targets ts \
--vector-glob 'LAY-L0-INST-*' --report instant.json
--vector ID и --vector-glob 'PATTERN' повторяются и объединяются;
опечатка или шаблон без совпадений — ошибка. Отчёт такого запуска partial,
пара инертности всегда проверяется целиком. Явный --outcomes сохраняет
проверку выбранных пинов, включая отказ при устаревшем хэше входов.
Без него development-запуск сверяет голдены без приёмки полного реестра.
Полная проверка реестра (не обычный TS-цикл):
python check_conformance.py --core-kit KIT --fixtures FIXTURES --targets py,ts,go \
--outcomes active-outcomes.json --timeout 180 --report conformance.json
Все совпадения и отказы требуют свежих пинов; лишний пин также ошибка.
recertify_registry.py закрепляет полный завершённый observation без повторной
сборки: проверяет хэш каждого execution-source и всего fixture payload,
полноту inventory, три цели, отсутствие ошибок и поимённую квалификацию
каждого утраченного совпадения. Частичный отчёт, изменённый источник,
неизвестный исход, crash/divergence и неквалифицированная потеря отвергаются.
В R.2 отдельно квалифицированы все 145 совпадений последней сертификации
и их объединение с прежним harness — 525 ID.
Принято DECISION-0188. Срез слоя L0: пакет Law DSL превращается в обычный
исходник на целевом языке, который считает без движка правил. Профиль —
core-executable (§8.4): ответ и статус, без доказательства, хэшей и
канонического документа.
Excel: цель xlsx выпускает самостоятельную книгу с формулами по отдельному
ограниченному профилю excel-calculator/0.1. Сборка, настройки и границы.
Это протокол workbook: книга пересчитывается в Excel, JSON-раннера у неё нет.
Устройство
CLIR (ir.json)
│
plan.py ВСЯ семантика среза и ВСЕ отказы; языка не знает
│
план (law-backend-plan/0.7) таблицы, правила, соединения, гарды, термы,
│ либо 0.8 (L1), 0.9 окна действия §31, собственные факты пакета;
│ у 0.8 — возможности, страты и фазы §111;
│ у 0.9 — агрегаты §59 и замыкания §70;
│ 0.10 с norm снят до W6;
│ у 0.11 — календарные функции §84–§86;
│ у 0.12 — Rational §35; у 0.13 — Quantity §49;
│ у 0.14 — политика округления §50;
│ у 0.15 — Boolean/Natural, границы месяца, `_` §98;
│ у 0.16 — датированные приоритеты §92.3 и `prepare`;
│ у 0.17 — условный терм §56 и вычисляемый аргумент тела;
│ у 0.18 — функции §46, параметры A3, `let`, `match`;
│ у 0.19 — канал суждения §47.3
├── targets/ts/emit.py → model.ts + api.ts (+ evaluate.ts, apiBase.ts, runtime.ts, runner.ts)
├── targets/py/emit.py → model.py + api.py (+ evaluate.py, api_base.py, runtime.py, runner.py)
├── targets/go/emit.py → model.go + api.go (+ evaluate.go, apiBase.go, runtime.go, runner.go)
├── excel_plan.py → targets/xlsx/emit.py → model.xlsx (профиль Excel, только план 0.7)
└── targets/{rb,rs,java,cs,kt,erl,ex,lua,swift,php,dart,scala,bsl}/emit.py —
Ruby, Rust, Java, C#, Kotlin, Erlang, Elixir, Lua, Swift, PHP, Dart,
Scala, встроенный язык 1С (BSL на OneScript): та же раскладка, свой
рантайм и раннер, только план 0.7
Цель — каталог targets/<цель>/ с эмиттером и дескриптором в нём же:
available() (тулчейн на машине), MODEL (путь модели в проекте),
layout(proj, main) (рантайм, раннер либо харнесс, файлы сборки языка),
build(proj) (команда сборки или None), run(proj, main) (argv-префикс).
Ворота, поставка и потребитель ветвятся по дескриптору, а не по языку;
--targets выбирает цели, по умолчанию ts,py,go, all в воротах и consumer —
все с протоколом runner и доступным тулчейном. Поставка ./law dev backend
также видит цель xlsx; её отдельный профиль проверяет check_xlsx.py.
Дескриптор PROTOCOL = "workbook" вместо runner предоставляет artifacts(plan, options) -> {имя: bytes} и PROFILE. Все артефакты готовятся до записи первого
файла. Паспорт фиксирует фактический профиль и хэши бинарных файлов. Ограничения
Excel и развёртка формул живут в excel_plan.py, сериализатор не решает правила.
Отказ живёт в плане, а не в эмиттере. Иначе один и тот же пакет означал бы в разных языках разное: где-то отказ, где-то тихо другой ответ. Незнакомое объявление, незнакомое поле правила или незнакомая форма терма дают не «меньше ответа», а ДРУГОЙ ответ — поэтому пропускать нельзя.
Инертная конструкция — единственное исключение, и оно доказывается, а не
предполагается (CODEGEN-COVERAGE-PLAN §1.1, W1). Манифест inert-nodes.json
перечисляет конструкции, которые присутствуют в пакете, но на ответ
поддержанных видов вопросов не влияют: source_work §28, anchor §33,
revision §32, entrenchment §92.3, factor_vocabulary и precedent_decl
§201, counterfactual_decl §186, поле правила visibility §23.2. План
пропускает ровно перечисленное (INERT_NODE_KINDS, INERT_RULE_FIELDS); у
каждой строки — пара векторов LAY-L0-INERT-<КОНСТРУКЦИЯ> / …-BARE над одной
программой, делом и вопросом, чьи голдены оракула совпадают по results,
positions, issues, conflicts, proofGraph (manifest и resultHash
различаются по построению). check_conformance требует обе половины среди
активных векторов, совпадение половины с конструкцией на каждой цели и
равенство документов; строка без свидетеля — отказ ворот (inert.py).
reference §30.2 в манифест НЕ входит: без применимой на legal_time редакции
оракул опустошает результаты (SOURCE_RESOLUTION_FAILED), и это отказ плана.
Проверено на векторе ERR-E0095-CLOSED-EDITION-RULE: пока план молча
игнорировал жизненный цикл редакции, порождённый код отвечал TRUE_ONLY там,
где голден даёт NEITHER. Ловят такие места только векторы.
Формат плана law-backend-plan/0.7 и law-backend-plan/0.8
Версия у формата есть, поэтому поля перечислены здесь, а не читаются из кода
генератора. Изменение состава полей меняет версию. Каждый эмиттер печатает
закрытый список версий (SUPPORTED_PLAN* в check_plan) и отвергает любую
другую, как и возможность плана вне своего CAPABILITIES: незнакомое поле
плана печаталось бы молча, а это другой ответ, не меньший. Сегодня ts,
py, go печатают версии 0.7–0.19, остальные 13 программных целей и xlsx —
только 0.7. Ворота начинают с отрицательной пробы — план версии 999 обязан
быть отвергнут всеми эмиттерами. Проба не ловит смену СМЫСЛА поля под
прежним номером: это держат только векторы.
История: 0.1 — без params у таблиц; 0.2 (09.09.2026) — таблицы несут
объявленные типы параметров для проверки аргументов дела §189; 0.3
(09.09.2026, ночь) — consts и bases верхнего уровня, вид Date в
типах и термах, вид enum для членов перечислений §38.
0.4 (10.09.2026) — арифметика §58: операции add, sub, mul, div,
mod и функции min, max, abs, pow, round; пары видов проверяются
планом статически по таблицам §58. 0.5 (14.09.2026) — keys у таблиц
(ключи отношений §45.1, раннер печатает KEY_CONFLICT) и filters у
правил (константа в аргументе атома тела). 0.6 — api; 0.7 — окна
редакций §92.3 и мир импортов (DECISION-0236). 0.8 (14.09.2026,
DECISION-0237) — план поражаемого слоя, описан ниже в своём разделе. План
без возможностей по-прежнему 0.7 и байтово тот же: у 343 планов,
построенных до 0.8 (векторы и снимки корпуса), отпечатки совпали.
Верхний уровень. planVersion — строка версии. package — паспорт из
CLIR (name, namespace, version, semanticHash); эмиттеры его не
читают, он нужен человеку и будущей поставке. world — зависимости мира
(name, namespace, version), excluded — id узлов, снятых проекцией
§92.3 на всей оси (информация для человека). tables, rules, facts,
api — ниже.
tables — по одной записи на объявленное отношение: pred (URN,
единственный ключ доступа во время исполнения), name (последний сегмент,
даёт имя переменной в порождённом коде), arity, params — объявленные
типы параметров по порядку (URN типа std либо типа-сущности). Тип каждого
параметра проверяется планом на входе в срез, а не только у атомов правил:
таблица с параметром вне среза (Rational, Instant, Date) не может хранить
значения дела, и отказ обязан жить в плане, а не всплывать в раннере одной
из целей. keys — ключи отношения §45.1 как списки позиций столбцов
(пустой список — ключей нет). Порождённый модуль после насыщения считает
группы строк с одинаковой проекцией на ключ; строки уникальны по ключу
строки, поэтому группа из двух и более строк — различные accepted-кортежи,
и на каждую такую группу раннер печатает один KEY_CONFLICT (§196). У
оракула в счёт идут утверждения и strict-выводы — то же множество, что в
таблицах среза. Ответ от конфликта не меняется: evaluator ничего не
выбирает и не удаляет (LAY-L0-KEYS).
rules — по записи на правило, в порядке CLIR:
| поле | что несёт |
|---|---|
name |
уникальное имя в порождённом коде: порядковый номер плюс последний сегмент id |
id |
исходный URN правила; идёт комментарием в порождённый код |
window |
null либо {start, end} — полуинтервал [start, end) по оси legal_time (§31) |
atoms |
что перебирать, по порядку; строка атома i связывается с переменной r{i} |
joins |
равенства повторной переменной: пары [[строка, столбец, тип], …] |
filters |
константы в аргументах атомов тела: {row, col, t, term} — ячейка обязана быть равна терму-литералу (eq рантайма, равенство значений) |
guards |
отсев: {op, l, r}, где op — lt, le, gt, ge, eq, ne |
head |
что положить: {pred, args} |
facts — собственные утверждения пакета: {pred, args}. Кладутся в
таблицы до насыщения.
Константа в теле. Оракул сопоставляет неперемённый аргумент атома тела
с ground-атомом по каноническим байтам терма — по значению И типу
(solver.solve), а рантайм среза сравнивает eq по значению. Поэтому тип
литерала обязан совпасть с объявленным типом слота статически: литерал
Integer в Decimal-слоте у оракула не совпадает ни с одной строкой, а
рантайм по величине ответил бы иначе — это отказ плана «тип аргумента тела
не совпадает с параметром §189». Член перечисления проверяется по
принадлежности слоту, а не по «типу члена»: одно имя члена бывает у
нескольких перечислений пакета (kz.corpus.land_code, FarmHousehold в
четырёх). Сущности типа не несут, как у оракула. Подстановочный _ §98
(E-0165) и терм с вычислением в аргументе тела — названные отказы.
Вектор — ERR-E0052-DECIMAL-CANON: price(v0, 110000 USD) в теле.
consts — константы §54 со значением: {id: {type, term}}. Раннер
разыменовывает const_ref в аргументах дела и запроса до исполнения
(§54.1: ниже ссылок нет) и сверяет тип константы с параметром §189 —
только у константы std-типа: оракул разыменовывает константы до сверки, и
константа-сущность становится entity_ref, который типа не несёт (до
15.09.2026 раннеры сверяли и её; у eu.pil.jurisdictions подтип с именем
пакет#Тип не находил базового — 3 ложных NEITHER).
bases — наследование сущностей {подтип: базовый}: константа подтипа
подходит параметру базового типа, как у оракула. Ссылка const_ref, не
стоящая в consts, — член перечисления §38 либо имя без объявления: оракул
оставляет её в ключе атома как есть, поэтому раннер берёт её значением-
идентичностью (вид enum), без проверки типа. Ссылка на функцию или
параметр A3 через const_ref — названный отказ плана.
Чужой тип пакет#Тип. Компилятор понижает algo.description::Algorithm
в имя algo.description#Algorithm, а не в URN объявления. Вид слота план
берёт у объявления namespace#Тип, где namespace — пакета мира с точно этим
именем; строки типов в params, consts и bases не меняются, потому что
оракул сравнивает их строками (facts._conforms). Имя без пакета в мире или
без объявления — вне среза. 15.09.2026 это открыло 27 снимков
(algo.* 15, mathlib.*, isabelle.order, arxo.*, eu.pil.jurisdictions).
Алиас типа §40 и сущности law.std.actors §261 (W2, часть 1, 27.09.2026).
Объявление type_decl с typeKind: alias прозрачно на исполнении, как у
оракула (facts._unalias, E-0097/E-0098): план ведёт таблицу aliases и
берёт имя типа за цепочкой алиасов в сигнатурах, константах, наследовании,
параметрах функций §46, let и параметрах A3. Цель алиаса компилятор пишет в
форме имя.пакета#Тип; она разрешается через паспорт мира (корень и
импорты), цель без пакета в мире остаётся строкой и уходит в отказ «тип
аргумента вне среза генератора: <цель>». Нормализуются ТОЛЬКО ссылки на
объявленные алиасы: сырые строки имя.пакета#Тип (абзац выше) не трогаются.
Типы Actor, NaturalPerson, LegalPerson, Organization,
PublicAuthority, Official, Court, Collective — сущности (вид text,
идентичность), как сущности пакета: entity_ref дела типа не несёт, §189 их
не сверяет. Event §79 и Instant §2.15 остаются отказом до частей 2–3 W2.
Свидетели — LAY-L0-ALIAS-STD-PARAM, LAY-L0-ALIAS-ENTITY-CHAIN,
LAY-L0-STD-ACTOR-PARAM; в корпусе алиасов 1255, из них 1250 с целью в
форме компилятора.
LegalContext, LegalRole, Jurisdiction и слот Interval<T> (W2, релиз 0.1.5).
Первые три — идентичности того же рода, что Actor: у оракула нет вида значения,
дело подаёт entity_ref. Слот Interval<T> §37 — непрозрачная идентичность:
литерала такого вида у оракула нет, интервальный терм дела раннер отвергает
поимённо («аргумент вне среза раннера: interval»), литерал-интервал в теле
правила — отказ плана. Свидетели — LAY-L0-STD-CONTEXT-JURISDICTION
(совпадение) и LAY-L0-INTERVAL-SLOT-TERM (закреплённый отказ раннера).
Ошибка головы поподстановочная (W5, errata E-0265, релиз 0.1.6). Ошибка
терма или агрегата головы снимает только свою подстановку: issue — по каждому
коду однажды, остальные подстановки применяются, как у оракула после E-0265.
Агрегат sum/min/max/only без политики empty в голове больше не отказ
плана (headAgg). Статус зависимого результата: NEITHER — статус кода (E-0105),
иная истинность — итог §181.2 (ruleErrorStatus раннеров). Свидетели —
LAY-L0-AGG-HEAD-EMPTY-FIRST, LAY-L0-AGG-HEAD-ALL-FILLED, ERR-E0265-*.
Instant §2.15 (W2, часть 2, 28.09.2026). Вид значения inst: запись
мгновения хранится как подана и служит идентичностью атома (E-0214), а
равенство и порядок берутся по МОМЕНТУ (E-0048): 12:00:00+05:00 и
07:00:00Z равны. §82.2 требует ASCII-григорианскую дату 0001–9999, полные часы/минуты/секунды
и обязательное смещение 00:00–23:59. Невалидная запись даёт TYPE_ERROR;
дробь произвольной длины сравнивается точно, без усечения. Запись без
смещения также не проходит admission;
Date с Instant не сравниваются (§57, у оракула DATE_INSTANT_MISMATCH) —
отказ плана при известных видах и рантайма при неизвестных. Функции §84.1:
hours_between/minutes_between — полных единиц со знаком, дробь к нулю;
add_duration(after, n unit) — целая Quantity секунд/минут/часов/суток,
ответ канонично в UTC без дробных секунд. Литерал Quantity длительности
сворачивается планом в пару (число, единица), как у календарных функций.
Возможность value:instant объявлена у py, ts, go; контракт рантайма —
случаи instant-*, hours-between-*, minutes-between-*, add-duration-*
в runtime-cert.json. Свидетели — LAY-L0-INST-EQ-MOMENT, LAY-L0-INST-ORDER,
LAY-L0-INST-HOURS-BETWEEN, LAY-L0-INST-MINUTES-BETWEEN,
LAY-L0-INST-ADD-DURATION.
Event §79 (W2, часть 3, 28.09.2026) — срез идентичности. Корни Event и
Action и типы-события пакетов (сущности с базой urn:law:std#Event) — слоты
идентичности, как сущности: событие в факте есть entity_ref на закреплённый
снимок (§79.1). Конструктор-запись события в факте раннер отвергает
поимённо («аргумент вне среза раннера: record»): его поля читает свёртка
§161.1, а это территория процедур (W7). Свидетели — LAY-L0-EVENT-REF-IDENTITY
(совпадение) и LAY-L0-EVENT-RECORD-VALUE (закреплённый отказ раннера).
Порядок проверок в цикле. Соединение и фильтр печатаются на уровне атома,
который их связывает, а не во внутреннем цикле: план не меняется, ответы и
отказы прежние (eq на text, enum, date, dec не отказывает; правило с
соединением над деньгами печатается прежним порядком). Декартово
произведение шести атомов тела algo.description без этого шло минутами на
пустом деле.
api (DECISION-0234) — поверхность модуля, выведенная планом по
правилам @arxo/law-forms: questions — pub-отношения с производящим
правилом, читающим в теле другой предикат; inputs — предикаты, достижимые
из вопросов и либо эмпирические, либо без производителя. У записи pred,
name (уникальное имя функции), params, kinds; у вопроса ещё inputs.
Цель с API и emit_api печатает по нему файл — устройство и контракт в
разделе «Единый вход и библиотека (DECISION-0423)» ниже. Над каждой функцией —
комментарий из меток отношения и производящих правил с якорями
@source локатор · редакция (поля labels и sources плана); в файле есть
реестры по имени.
Единый вход и библиотека (DECISION-0423)
Один вычислительный вход. У ts, py, go семантика ответа живёт в одном
рукописном модуле цели — evaluate.py, evaluate.ts, evaluate.go: дело и
вопрос в канонической форме §168/§172 (той же, что у векторов и оракула) →
ответ исполняемого профиля. В нём разбор сырых литералов §208, сверка
аргументов дела §189, разворот контекста (правовое время, политика срока,
снимок календаря), насыщение, issues и лестница статусов вопроса (конфликт
эффектов §127 → конфликт ключа E-0242 → запрос судье §47.3 → ошибка терма
E-0105/§181.2). Раннер — транспорт JSON к этому входу, API — адаптер
аргументов к нему же, поэтому API и раннер отвечают одинаково по построению.
До 0.2.0 часть этой семантики жила только в раннере, и API на одном деле
давал другой ответ (Decimal в слоте сущности: раннер NEITHER/TYPE_ERROR,
API TRUE_ONLY/COMPUTED).
Состояние на вызов. Модель — фабрика: эмиттер оборачивает тело модуля
модели в new_model() (Python), newModel() (TypeScript, Go); таблицы,
опоры, кандидаты и issues — локальные переменные вызова, правила — замыкания
над ними, тела правил не переписываются. Контекст вычисления: у Python —
contextvars, у TypeScript — контекст, который синхронный evaluate ставит на
время вызова и снимает в finally, у Go — evalContext экземпляра модели, чьи
методы в фабрике затеняют одноимённые функции рантайма (legalTime,
add_legal_term и соседи). Глобального правового времени и мьютекса нет:
вызовы из потоков Python и горутин Go независимы.
Значения входа — литерал-термы §53. Конструкторы общей части API
(api_base.py, apiBase.ts, apiBase.go) строят ту же запись, что векторы:
integer, natural, decimal, money, quantity, rational, text,
boolean, date, instant, entity, member (в Go — IntegerOf,
DecimalOf, … с суффиксом Of: имена типов рантайма заняты). Decimal и Money —
из десятичной строки по лексике §208, без float; валюта обязательна. Значение
языка без конструктора переводится только по объявленному типу параметра
(строка в слоте сущности — entity, в слоте Text — text, целое в слоте
Integer — integer); вид, который по типу слота не читается однозначно, —
ошибка формы вызова. Литерал-терм с чужим типом проходит в evaluate, и там
сверка §189 даёт TYPE_ERROR, как у раннера и оракула.
Ответ одной формы. Answer у L0 и L1 и у всех трёх целей: query_id,
result_kind (PROPOSITION у вопроса истинности, COLLECTION у строк),
truth_status, evaluation_status (перечень §175), issues (коды),
judgment_requests, rows (литерал-термы). Python — frozen dataclass,
TypeScript — readonly размеченное объединение по resultKind, Go — структура.
rows_* идёт тем же входом (внутренний вид rows, которого протокол раннера не
знает) и отдаёт тот же конверт.
Ошибки. Ошибка формы вызова — InputError; названный отказ среза —
Refused (Python, TypeScript) и *RefusedError (Go, errors.As), паники на
границе нет; семантический TYPE_ERROR — issue и статус ответа. В Go ошибка
перевода аргумента запоминается в факте и возвращается вызовом Ask*.
Функции. Python: fact_<вход>, negated_<вход> (L1), ask_<вопрос>(facts, on, …, *, query_id=None), rows_<вопрос>, реестры QUESTIONS, INPUTS,
NEGATED. TypeScript: объекты facts, negated, ask, rows, реестры
questions, inputs, negatedInputs. Go: Fact<Имя>, Negated<Имя>,
Ask<Имя>, Rows<Имя>, реестры Questions, Inputs, Negated.
Имена из StableId (0.3.0). План даёт каждому вопросу и входу нейтральное
имя — локальную часть StableId: ASCII-имя как прежде, буквы других
письменностей сохраняются (NFC), прочие знаки сворачиваются в _. Эмиттер
делит имя на слова (по _ и горбам camelCase с учётом регистра Unicode) и
печатает его по правилу языка: Python — snake_case, TypeScript — camelCase,
Go — PascalCase из одних букв и десятичных цифр (идентификатор Go не
принимает комбинирующих знаков). Совпадения ПОСЛЕ преобразования разводятся
суффиксом (_2 у Python, 2 у TypeScript и Go) в порядке плана, то есть по
StableId. Реестры по строке и идентификатор вопроса по умолчанию
(urn:query:api:<имя>) держат нейтральное имя — оно одинаково у всех целей.
До 0.3.0 кириллическое имя превращалось в подчёркивания: у пакетов ru-tk-*
Go-API ломался на одинаковых FactX, а TypeScript — на одинаковых именах
таблиц модели; внутренний слаг с буквами вне ASCII теперь получает 8 знаков
SHA-256 локальной части, а повторное совпадение имени таблицы после префикса
пространства имён — названный отказ плана.
Проверка. check_api.py (arxo-codegen-check-api, шаг приёмки
ci/verify.py) печатает API-пакеты комплекта на целях с API и исполняет каждое
задание раннером и харнессом API (targets/<цель>/apicheck.*, у Go — второй
бинарь под тегом apicheck): положительное, с отрицательным фактом L1, с
литералом чужого типа (§189), с синтетическим ключом §45.1 при читающем и
независимом вопросе. Исходы обязаны совпасть у API и раннера каждой цели и у
целей между собой; затем пакет всех заданий с повтором первого исполняется
одним процессом последовательно и параллельно, а канарейка портит статус и
issues в api_base.py — расхождение обязано найтись. Харнессам запрещено
достраивать отсутствующие поля ответа. На коде 0.1.6 эта проверка даёт 55
расхождений (45 — литерал чужого типа, 10 — конфликт ключа).
Терм — одна из четырёх форм:
| форма | поля |
|---|---|
| ячейка строки | {k: "var", row, col, t}, где t — money, dec, text, bool, date или enum |
| литерал | {k: "lit", t: "money", v, cur}, {k: "lit", t: "dec", v}, {k: "lit", t: "text", v}, {k: "lit", t: "date", v}, {k: "lit", t: "enum", v} |
| бинарная операция | {k: "bin", op, l, r}, op — add, sub, mul, div, mod |
| вызов функции | {k: "call", fn, args}, fn — round, min, max, abs, pow, div_round; в плане 0.14 у round и div_round — ak, статические виды аргументов (DECISION-0259) |
Таблицы видов §58 в срезе (Integer, Decimal, Money; Rational и Quantity
вне среза). add/sub/min/max — только совпадающие виды. mul —
скаляр §49: Integer и Decimal масштабируют Money, два Money не
перемножаются. div — Decimal/Decimal и Money/Money одной валюты дают
Decimal, Money/Decimal — Money; Integer/Integer даёт Rational и
отвергается планом. mod и pow — только Integer, остаток евклидов,
показатель 0..4096, результат в 64-битном диапазоне. abs сохраняет вид,
round над Integer — тождество (E-0110). Пара вне таблицы — отказ плана,
как TYPE_ERROR у оракула. Вид результата, зависящий от ЗНАЧЕНИЯ, — не
10-гладкое частное, INEXACT_DIVISION, деление на ноль, предел pow —
решает рантайм названным отказом: оракул на тех же входах даёт issue и
RUNTIME_ERROR, а не ответ, поэтому отказ здесь честен, а ответ был бы
другим.
Числа во всех литералах — СТРОКИ: десятичная запись не проходит через двоичную плавающую точку ни в плане, ни в порождённом коде.
Поражаемый слой L1 (DECISION-0237)
Возможности. План сначала определяет, что программе нужно сверх L0:
defeasible (сила defeasible/defeater §104), negation (отрицательная
голова, литерал тела или собственный факт §99/§113), priority
(priority_rule §106), status:<вид> (статусные тесты §65 not_known,
unknown, refuted, monotone, supported). Вызывающий может добавить
возможность сам: ворота просят negation, когда дело несёт отрицательный
факт. Пустое множество — прежний план 0.7. Непустое — план 0.8 с полем
capabilities (отсортированный список). Дескриптор цели объявляет
CAPABILITIES; deliver.emit_project сверяет их ДО записи первого файла и
отказывает поставке названной причиной «цель rb не поддерживает возможности
плана: …» (код 2). Сейчас 0.8 печатают ts, py, go; остальные 13
целей его отвергают — проба ворот это проверяет.
Поля плана 0.8 сверх 0.7. У правила: strength; у атома — accept,
сырые статусы §62 строки, при которых генератор её перечисляет
(established — TRUE_ONLY, monotone/supported — TRUE_ONLY, BOTH);
checks — литералы, которые не перебираются, а проверяются над уже
связанными переменными: {pred, accept, args}, где accept уже учёл
полярность литерала (§63) и вид теста; у головы — polarity; subst —
значения всех переменных тела, идентичность применения. У факта —
polarity. Верхний уровень: strata.strict (списки имён правил по рангам
строгого слоя), strata.defeasible (по рангам §110), priorities (пары
«выше, ниже» транзитивного замыкания §106 по именам правил), schedule —
фазы §111: strict, closure (зарезервирована, policies: []), затем на
каждую поражаемую страту candidates (с rules), defeat, surviving,
strict, status. Эмиттер, встретив неизвестную фазу или closure с
политиками, отказывает.
Что решает план (всё структурное). Генераторы — положительные
established/monotone литералы тела по порядку; всё прочее — проверки,
и переменная, не связанная генератором, — отказ §190/§113 (отсутствие не
связывает). Ground-тело без генератора допускается. Ранги строгого слоя —
порт strict.strict_ranks, поражаемого — порт defeasible.stratify с
выравниванием голов обеих полярностей и дефитеров (E-0078/E-0080).
Названные отказы:
| причина | когда |
|---|---|
программа не стратифицируема (§110, NON_EXECUTABLE_UNSTRATIFIED) |
цикл предикатного графа с немонотонным ребром; ранги не сходятся |
рекурсия с порождением значений арифметикой (DECISION-0237 п. 11) |
голова с bin/call в той же компоненте, что чтение тела; действует и для L0 |
дефитер без обычного кандидата той же полярности (§110 п. 5, NON_EXECUTABLE_STRATUM_BARRIER) |
нет производителя либо его окна редакций §92.3 не покрывают окно дефитера |
цикл приоритетов (§106, PRIORITY_CONFLICT) |
цикл безусловных рёбер; отказ, а не совпадение с оракулом |
условный приоритет (§117/§118) |
condition не true либо priorityKind не direct |
датированный приоритет (§92.3) |
окно редакции приоритета не вся ось |
поздний производитель (§111, LDC-E4103) |
strict-правило читает статусно (не monotone) предикат с поражаемым производителем; strict not_known/unknown/refuted над строгой цепочкой к поражаемому выводу; поражаемое правило читает предикат (или делит голову), строгая цепочка которого завершается не ниже его страты |
статусный тест вне среза генератора: conflicted |
conflicted, opposed — оракул их не исполняет |
объявление вне среза генератора: closure_policy/None, …: interpretation*, …: reference/None |
замыкание §70, прочтения §156, динамическая ссылка §30.2; инертные объявления манифеста inert-nodes.json сюда не попадают |
Модель (одинаково в py, ts, go). Строки таблиц и параллельно —
их ключи; опоры — биты на ключ строки: strict/asserted +/− и
surviving-defeasible +/−. Статус §62 выводится при чтении из битов.
Strict-правило ставит бит своей полярности; поражаемое правило кладёт
кандидата в таблицу кандидатов страты с ключом «имя правила + ключ
подстановки». defeat — локальный helper над полным снимком кандидатов:
группа — (предикат, ключ строки), кандидат побеждён strict-битом
комплемента (§107.1), противоположным обычным кандидатом с ребром
приоритета над ним (§107.2) или дефитером той же полярности, над которым у
кандидата ребра нет (§107.3); побеждённые не удаляются по ходу обхода.
Выжившим ставится surviving-бит. Страты печатаются циклами по schedule.
Контракт рантайма (восемь функций) и сертификация не менялись.
Раннер и API. L1-модель принимает отрицательные факты дела; вопрос
truth отвечает статусом §62 атома, отрицательный вопрос зеркалит стороны
§63. collect и rows_* перечисляют только TRUE_ONLY-строки. API
отдаёт статус буквально: у Python (status, issues), у TypeScript
Answer.status типа Status, у Go Answer.Status; отрицательные входы —
negated_*, negated.*, Negated<Имя> и реестры NEGATED,
negatedInputs, Negated. Входы вопроса считаются по чтениям всех правил,
включая дефитеры и проверки; дефитер производителем вопроса не считается.
L0-модели получили тот же интерфейс раннера (LAYER, установленные строки,
статус строки, отказ на отрицательный факт) без смены поведения.
Ворота. layer: L1 исполняется наравне с L0; голден без результата у
L1-вектора обязан быть отказом плана с той же причиной (structural: <код> в манифесте: NON_EXECUTABLE_UNSTRATIFIED,
NON_EXECUTABLE_STRATUM_BARRIER, LDC-E4101). Пол MIN_CHECKED_L1
отдельный. Фикстуры verify/ci/gates/backends/l1_fixtures.py: семь
программ с ответом из прозы, каждая в перестановке правил и фактов и с
канарейкой — той же программой без решающей нормы, чей ответ обязан
отличаться (обе стороны выжили, strict против defeasible, дефитер
преодолён и не преодолён, один выживший среди побеждённых, умолчание §113,
монотонная рекурсия); три структурных контрпримера (default-цикл, поздний
производитель, дефитер без кандидата). API-шаг идёт и на L1-пакетах
doctrine-ius-privatum, ru-zolotaya-rybka с заданиями, где первый вход
подан отрицательным фактом.
Агрегаты §59 и замыкания §70 (DECISION-0239)
Возможности и версия. aggregate — агрегат в теле или голове правила,
closure — узел closure_policy. План с любой из них — law-backend-plan/0.9
(поля 0.8 плюс ниже); без них план остаётся 0.8 или 0.7 байтово (отпечатки
всех построенных до правки планов совпали). Печатают ts, py, go.
Поля 0.9. У правила steps — порядок тела, как его выбирает solve
оракула: {gen: i} открывает цикл по атому, {check: i} и {guard: i}
стоят там, где связаны их переменные; fallible — в гарде есть агрегат,
способный дать ошибку значения; addends — агрегаты sum монотонных гардов
для проверки знака слагаемых. Верхний уровень: aggregates — подпланы
{name, op, params, atoms, joins, filters, checks, guards, steps, element, distinct, empty}, где params — виды внешних переменных, а терм
{k: "param", i, t} читает i-ю из них; терм {k: "agg", fn, args, t}
вызывает подплан. closures — {name, id, pred, domain, window}; окно по
дню §2.15 переведено в полуинтервал. Расписание: strict, затем на каждый
уровень E-0113 closure с policies и снова strict, затем страты L1.
У фазы strict может быть waiting — имена strict-правил, которые этот
проход не исполняет: их замыкания ещё не материализованы (errata E-0174).
Поле печатается только непустым, поэтому прочие планы 0.9 байтово прежние.
Эмиттер печатает для каждого набора waiting константу страт без этих
правил, а незнакомое поле фазы отвергает.
Семантика. Агрегаты count, sum, min, max, only над comprehension
§52.1: генератор перебирает установленные строки, distinct — по ключу
значения, collect all — со повторами; count даёт Integer, остальные —
вид элемента (Integer, Decimal, Money). only — функциональный lookup §51
(errata E-0256): значение, если различное значение ровно одно (различие — по
тому же ключу, что distinct, поэтому над collect all кратность
безразлична); пусто — EMPTY_AGGREGATE, два и более различных —
CARDINALITY_CONFLICT. Он всегда фоллибелен: в гарде — ошибка значения G3
ниже, в голове правила — поподстановочная ошибка головы (E-0265, W5; до
релиза 0.1.6 — отказ плана). Политики у only нет:
options — отказ плана (у оракула TYPE_ERROR). План с фоллибельным
агрегатом несёт backchain: ошибка агрегата правила-кандидата доезжает до
статуса вопроса truth по E-0105 (NEITHER + RUNTIME_ERROR). Перечисление — ребро completion
(+1 в рангах обоих слоёв). Замыкание ставит strict-негатив члену домена
(TRUE_ONLY), у которого нет strict/asserted positive-опоры; strict-негатив
по §107.1 побеждает поражаемого кандидата.
Ожидание замыкания (E-0174). Strict-правило, тест которого опровергается
негативом замыкания, ждёт материализации этого замыкания. Это unknown(P)
любой полярности, not_known(not P) и перечисление в генераторе агрегата.
План переносит rules.closure_waits оракула: зависимости чтения делятся
по §65, ожидание транзитивно через строгих производителей. Правило ждёт до
уровня своего старшего замыкания. Голый not P, established и monotone
отрицательного литерала не ждут: замыкание делает их тест только истинным.
Ошибки значения (G3). sum/min/max без options.empty над пустой
коллекцией в гарде: правило копит выводы и при ошибке не применяет ни одного,
модель печатает EMPTY_AGGREGATE один раз на правило; отрицательное
слагаемое монотонного гарда sum — MONOTONE_GUARD_NEGATIVE_ADDEND и
пропуск подстановки. Коды идут в issues раннера и API и сверяются с
голденом (BACKEND_ISSUES).
Удержание issue монотонного гарда (errata E-0198) в срез НЕ переносится, и
переносить нечего. Ядро с 20.09.2026 предъявляет ошибку проверки
МОНОТОННОГО АГРЕГАТНОГО ГАРДА §111 по состоянию НЕПОДВИЖНОЙ ТОЧКИ страты:
ошибка промежуточного прохода, не повторившаяся на последнем, в документ не
попадает. Удержание наблюдаемо ровно там, где коллекция гарда РАСТЁТ внутри
его страты, то есть где generator читает ВЫВОДИМЫЙ предикат, — а это и есть
отказ плана G2 из таблицы ниже. Замер 20.09.2026 живьём на целях ts,py,go:
пять векторов errata (ERR-E0198-GUARD-EARLY-EMPTY-SILENT, …-SILENT-02,
…-GUARD-FIXPOINT-EMPTY-SPEAKS, …-BLOCKS-02, …-GUARD-LATE-ERROR-SPEAKS)
отвергнуты планом с той же причиной, что и семейство ERR-E0116-*; шестой,
ERR-E0198-EMPIRICAL-GUARD-UNCHANGED, в срезе И СОВПАЛ — у него generator
читает одну эмпирику, коллекция заморожена входом дела, и errata его не
касается по собственной границе. Отказ закреплён дважды: структурной
фикстурой monotone-guard-derived и шестью строками манифеста. Поэтому
абзац G3 выше остаётся верным дословно: у среза «правило копит выводы и при
ошибке не применяет ни одного» относится к ЗАКРЫТОЙ коллекции, а растущая в
срез не входит. Появится акт, ради которого G2 откроют, — удержание придётся
переносить тем же изменением, и это условие входа названо здесь, а не в
календаре.
Вид empty-политики §59 (errata E-0195) сверяется в обеих точках. В
правиле — планом: вид политики обязан совпасть и с видом результата,
выведенным планом из терма элемента, и с ОБЪЯВЛЕННЫМ типом проекции
comprehension §52.1 (variable.type.name — тот самый носитель, с которым
сверяется оракул: он не зависит от числа решений generator-а). Расхождение
любого из двух — отказ плана, потому что у оракула тот же вход даёт
TYPE_ERROR, то есть ДРУГОЙ ответ, а не меньший. В вопросе term — раннером
каждой цели: политика не-value и политика чужого вида над ПУСТОЙ коллекцией
дают TermError TYPE_ERROR (ответ без значения, evaluationStatus
TYPE_ERROR, issue TYPE_ERROR), совпавший вид и непустая коллекция
отвечают как прежде. Текста issue порождённый модуль не печатает вовсе —
байтовый контракт среза здесь КОД, и он тот же, что у оракула. До правки
20.09.2026 все три цели отвечали на коллекцию Money с политикой Integer
значением Integer 0 и COMPUTED. Векторы ERR-E0195-EMPTY-POLICY-* этого
места не достают: их comprehension несёт СВЯЗКУ, и раннер отказывает раньше
агрегата, — поэтому норму держат три пробы ворот (EMPTY_POLICY_PROBES в
check_backends.py) на том же пакете и деле без связок: свидетель нормы и две
пробы против переусердствования.
Отказы 0.9.
| причина | когда |
|---|---|
агрегат вне среза генератора: average |
операция вне count/sum/min/max/only |
агрегат only с options вне среза генератора (§51, errata E-0256) |
у only задана политика; у оракула тот же вход — TYPE_ERROR |
вычисляемый элемент comprehension вне среза генератора (§52.1) |
элемент не переменная и не литерал |
монотонный агрегатный гард (E-0116) над выводимым предикатом |
гард, который оракул считает монотонным, читает выводимый предикат (G2); над одними входами — исполняется |
вид empty-политики агрегата не совпадает с видом элемента коллекции (§59, errata E-0195) |
вид политики разошёлся с видом результата плана либо с объявленным типом проекции comprehension; у оракула тот же вход — TYPE_ERROR |
агрегат с ошибкой значения над незавершённым входом |
фоллибельный гард strict-правила читает то, что в его страте ещё растёт |
замыкание §70 вне среза генератора (NON_EXECUTABLE_CLOSURE) |
предикат и домен не одной сигнатуры либо домен не const_ref |
замыкание §70 над поражаемым производителем |
у предиката или домена поражаемый либо поздний производитель (G5) |
программа не стратифицируема (§110, …) |
цикл через completion или вершину замыкания |
Фикстуры ворот: count-over-derived, empty-sum-issue (канарейка — те же
статусы без issue), closure-negative, closure-strict-positive,
closure-unknown-reader и closure-transitive-default (E-0174: ответ
NEITHER, канарейка без замыкания — TRUE_ONLY); структурные
completion-cycle, monotone-guard-derived, closure-over-defeasible.
Нормативный runtime — отказ до W6
Текущая семантика норм использует ранги E-0325/E-0328–E-0332/E-0339.
По выбору владельца она переносится в W6. План отвергает наличие шаблона
нормы или нормативной головы с NORM_RANKS_UNAVAILABLE для всех вопросов;
прямой evaluate(..., {kind: "positions"}) — POSITIONS_UNAVAILABLE до
создания модели. Hand-built план с norms либо возможностью norm
отвергается и эмиттером. Прежней лестницы статусов и материализации эффектов
в трёх эмиттерах нет. Обычный truth о цели эффекта эту границу не обходит.
Календарные функции §84–§86 (DECISION-0245)
Возможности и версия. calendar:days_between, calendar:period
(add_calendar_period, add_legal_term календарных единиц),
calendar:business (add_business_days, add_legal_term дневных единиц).
План с любой из них — law-backend-plan/0.11; 0.7–0.10 байтово прежние
(отпечатки 1656 планов совпали). days_between безошибочна над слотами Date и
модели не меняет: пакет только с ней остаётся L0-моделью. Функции с ошибкой
значения требуют накопления выводов и печатаются L1-моделью 0.9. Печатают
ts, py, go; прочие цели отвергают план пробой версии.
Термы. {k: "call", fn, args}; счётчик — {k: "qty", v, unit}, только
литерал Quantity с единицей, допустимой функции (E-0029/E-0109), целый.
Не Date, чужая единица, дробный счётчик — отказ плана (у оракула всегда
TYPE_ERROR). add_legal_term §86.1 заменяется одной из двух операций по
единице. Места: гарды (cal у гарда), головы (headFallible у правила),
границы окон позиций L2 ({k: "calbound", term} либо {k: "calbound", error}, когда граница не Date).
Окружение. semanticVersion CLIR, deadlinePolicies (узлы
deadline_policy по id), calendars — снимки calendar_snapshot с
датасетом (покрытие, недельный график, исключения) либо кодом ошибки загрузки:
байты ресурса сверяются с datasetHash и схемой calendar-dataset при
построении плана; у вектора байты — calendar.resource.json рядом. Раннер до
вывода разворачивает профили контекста §89.1, выбирает политику
(context.deadlinePolicy: у CLIR 0.1 объект, у 0.2 ссылка на узел) и снимок
(options.calendarSnapshot; два снимка без выбора — отказ
AMBIGUOUS_CALENDAR). Потребитель закрепляет встроенную политику сценария
узлом программы, как корпусный путь оракула (kz.engine._pin_deadline_policies).
Ошибки. Рантайм — порт compute_deadline и Calendar по порядку
проверок; коды MISSING_POLICY, DEADLINE_POLICY_INVALID,
MISSING_CALENDAR, CALENDAR_OUT_OF_RANGE, CALENDAR_DATASET_INVALID,
CALENDAR_DATASET_HASH_MISMATCH — issues модели. Гард: код ловится по
подстановкам, правило на проходе не срабатывает; два разных кода — отказ
рантайма. Голова: ошибка снимает только свою подстановку — issue по каждому
коду однажды, остальные подстановки применяются (errata E-0265, W5; до
релиза 0.1.6 ошибка у части подстановок была отказом рантайма). Граница окна:
issue и граница «нет». Фоллибельное правило обязано читать завершённое ниже
своей страты. Вопрос truth с ответом NEITHER получает статус E-0105:
раннер обходит backchain (правила с разыменованной головой и литеральными
конъюнктами) от цели, собирает коды ошибок правил-кандидатов и берёт
старший статус (MISSING_INPUT, MISSING_POLICY, …).
Фикстуры ворот: business-days-holiday (канарейка без исключения календаря),
calendar-month-end и window-calendar-bound (без политики),
guard-out-of-range, days-between-l0.
Rational §35/§58 (DECISION-0252)
Возможность и версия. value:rational получает программа, в которой
Rational может появиться: параметр отношения, литерал или константа Rational,
Integer/Integer, операция над Rational, а также значение-зависимое частное
Decimal/Decimal и Money/Money. Статический вид последнего виден только при
компиляции терма, поэтому build_plan строит план дважды: первый проход
отмечает встречу, второй строит law-backend-plan/0.12 модели L1 0.9. Планы,
где Rational не возникает, байтово прежние. Печатают ts, py, go.
Виды. Статический вид терма — Integer, Decimal, Money, Rational
либо динамический Decimal|Rational. Пара, у которой все исходы у оракула
TYPE_ERROR (Rational с Decimal или Money, Rational/Integer, mod не над
целыми, round над Rational), — отказ плана; пара с динамическим операндом
получает вид своих успешных исходов. Сравнение Rational с иным видом — отказ.
Поля 0.12. У терма bin — lk, rk: статические виды операндов (i,
d, m, r, n), по ним рантайм arith решает пару §58. Литерал —
{k: "lit", t: "rat", v: "n/d"}. У гарда с возможной ошибкой значения — err
(механика cal), у правила — headFallible и kindChecks: [[позиция, "d"|"r"]]:
динамический вид в слоте Decimal либо Rational сверяется по значению, чужой
вид — issue TYPE_ERROR по ключу (правило, предикат, позиция, вид) и пропуск
подстановки (E-0077). backchain — у каждого плана 0.12 (статус E-0105).
Ошибки. DIVISION_BY_ZERO, INEXACT_DIVISION, TYPE_ERROR — issues модели
по фазам DECISION-0245 п. 6. Расхождение валют денег не фоллибельно, как и
раньше: CURRENCY_MISMATCH — названный отказ раннера. Правило с фоллибельным
термом, читающее незавершённое в своей страте, ошибку не ловит: момент ошибки
у оракула зависел бы от хода фикспойнта, и она становится названным отказом
раннера. Вопрос term исполняет раннер сам: ошибка значения — RUNTIME_ERROR
с issue у любого плана. Rational в деле и вопросе — только канонической
записью §168.1, иная — отказ раннера.
Канарейки значений. Язык фикстур L1 деления и Rational не знает, поэтому
решающие нормы плана 0.12/0.13 держит VALUE_CANARIES в check_backends.py:
у векторов LAY-L0-RAT-*/LAY-L0-QTY-* из плана снимается kindChecks,
err, headFallible либо статический вид операнда деления, и модуль цели py
обязан разойтись с голденом — иначе ворота падают: норма не видна.
Quantity §49 v1 и счётчик-связыватель §86.1 (DECISION-0256)
Возможность и версия. value:quantity получает программа, где Quantity —
значение первого класса: параметр отношения, литерал или константа вне
литерала календарного счётчика, операция над Quantity, счётчик-связыватель.
План — law-backend-plan/0.13 модели L1 0.9; возможность независима от
value:rational, но Quantity/Quantity даёт вид Decimal|Rational, и такой
план несёт обе. Календарный план со счётчиком-литералом остаётся 0.11.
Сборка — тот же второй проход build_plan (value_caps).
Виды и поля. Статический вид Quantity без тега, код операнда q.
Литерал — {k: "lit", t: "qty", v, unit}. Пары §58 — порт values.binary:
пара, у которой все исходы у оракула TYPE_ERROR (Q×Q, Quantity с Money или
Rational, Q/Integer, Decimal/Q, mod, сравнение с иным видом), — отказ
плана. Счётчик-связыватель календарной функции — {k: "qtyvar", fn, term}:
рантайм counter проверяет вид, единицу функции и целочисленность; у
add_legal_term со связывателем план несёт calendar:period и
calendar:business, ветвь выбирает единица на деле.
Ошибки. Фоллибельны Q±Q, сравнение и min/max двух Quantity, деление:
DIMENSION_MISMATCH (разные теги), TYPE_ERROR (разные теги в частном — раньше
нуля), DIVISION_BY_ZERO, INEXACT_DIVISION — issues модели; статус E-0105 и
вопроса term у кодов несовместимости видов — TYPE_ERROR. Равенство при
сопоставлении фактов и ключах — «не равно» без issue. Расхождение валют денег
не фоллибельно (DECISION-0252) — асимметрия названа в DECISION-0256.
Политика округления §50: round и div_round (DECISION-0259)
Возможности и версия. value:div_round получает программа с любым
div_round; value:round — программа с round, у которого точность или режим
не литерал, режим не HALF_UP либо значение динамического вида
Decimal|Rational. Любая из них — law-backend-plan/0.14 модели L1 0.9; сборка —
тот же второй проход build_plan (value_caps). Программа с одним литеральным
round(…, n, "HALF_UP") остаётся прежней версии байтово и печатает прежний
round.
Виды и поля. У вызова round и div_round в плане 0.14 — ak: статические
виды аргументов (i, d, m, q, n; t — Text режима). Рантайм не
угадывает вид по значению: round над Integer — тождество Integer (E-0110).
Отказ плана — там, где у оракула всегда TYPE_ERROR: div_round вне пар
Money/Decimal, Quantity/Decimal, Decimal/Decimal, Money/Money
(E-0036, E-0170), Rational в аргументе, точность не Integer и не Decimal, режим
не Text, литеральная точность дробная, отрицательная или у div_round больше
34, литеральный режим вне семи. Динамический вид проверяет рантайм.
Ошибки. TYPE_ERROR, CURRENCY_MISMATCH, DIVISION_BY_ZERO — issues модели
по фазам DECISION-0245 п. 6, в порядке проверок оракула. round фоллибелен при
нелитеральной политике или динамическом виде, div_round — всегда, кроме
ненулевого литерального делителя при литеральной политике и паре не
Money/Money. Расхождение валют у div_round — issue, у оператора / —
прежний отказ (DECISION-0252 п. 4); асимметрия названа в DECISION-0259.
Решающие нормы плана держат канарейки VALUE_CANARIES над LAY-L0-RND-*:
err, headFallible, литеральный режим, литеральная точность, ak.
Boolean, Natural, границы месяца и _ (DECISION-0266–0268)
Возможности и версия. value:boolean, value:natural
(DECISION-0266), calendar:month_bound (DECISION-0267), wildcard
(DECISION-0268). Любая из них — law-backend-plan/0.15; модель не меняется,
и эмиттер узнаёт её по полям, как у 0.11 (schedule — L1, aggregates —
0.9). Планы без этих возможностей байтово прежние (отпечатки 1825 из 1869
путей; остальные — новые планы либо смена первой причины отказа).
Boolean. Литерал {k: "lit", t: "bool", v}, ячейка вида bool, в
деле — только JSON-булево (иное — названный отказ раннера). Равенство по
значению, порядок не определён: гард с lt…ge над Boolean или Boolean
против иного вида — отказ плана (у оракула всегда TYPE_ERROR,
LAY-L0-BOOL-ORDER); арифметика — отказ плана. Ключ строки b:true отличен
от Integer 1 и Text "true". Вопрос term: сравнение только eq/ne.
Natural. Ячейка вида dec, тип-строка urn:law:std#Natural в params.
Арифметика и статические виды считают Natural как Integer (_num), вид
результата — Integer, как у оракула (Typed integer). Сверка §189 тип-строк
без нормализации: Integer в Natural-слоте дела — TYPE_ERROR и утверждение
не принято (LAY-L0-NATURAL-SLOT-INTEGER); Integer-терм в Natural-слот
головы и Natural-ячейка в Integer-слот — отказ плана (E-0077,
LAY-L0-NATURAL-INTO-INTEGER-SLOT); переменная Natural-ячейки в Natural-слот
сохраняет запись (LAY-L0-NATURAL-HEAD-COPY). Отрицательное значение в деле
— названный отказ раннера.
Границы месяца §84.2. {k: "call", fn: "month_start" | "month_end", args: [Date]} — чистая функция над Date без политики §86 и снимка §85
(values.month_bound_value), не фоллибельна и накопления 0.9 не требует; не
Date статически или арность не 1 — отказ плана. В вопросе term арность и
вид — TermError TYPE_ERROR (ERR-E0084-MONTH-BOUND-ARITY, -KIND).
_ §98. У атома wild (столбцы _) и keep: по столбцу _ нет ни
фильтра, ни соединения, а на уровне цикла атома эмиттер пропускает строку с
уже виденной проекцией на keep — строки, различающиеся только в _, дают
одну подстановку (solver.solve, E-0165 MANY-ONE-APPLICATION). Множество
создаётся заново на каждой подстановке внешних атомов; полностью связанный
литерал с _ в теле 0.9 остаётся генератором на своём шаге. _ под
отрицанием, в статусном тесте не из GENERATING и в голове — отказ плана.
Датированные приоритеты §92.3 и подготовленный контекст (DECISION-0269)
Возможность и версия. priority:dated получает план, где узел
priority_rule датирован якорем на редакцию; версия —
law-backend-plan/0.16 модели L1. Планы без датированных рёбер байтово
прежние.
Замыкание с окнами. У оракула проекция §92.3 снимает неприменимые узлы
приоритета до замыкания (editions.project_editions,
defeasible._priority_closure), поэтому окно ребра участвует в замыкании:
ось права делится границами окон датированных рёбер на отрезки, на каждом
строится замыкание Уоршелла по активным рёбрам, пара «выше, ниже» получает
объединение отрезков, где достижима (_priority_windows). Пары на всей оси
— priorities, как прежде; остальные — datedPriorities: [выше, ниже, окна]; у норм-правил L2 — normPriorities и datedNormPriorities. Цикл на
отрезке — отказ плана с названным отрезком; прерывистое окно исходного ребра
(две и более редакции с разрывом) — отказ. Окно ребра с окнами правил-сторон
не пересекается: путь замыкания через снятое проекцией правило держится по
id, как у оракула (LAY-L1-PRIORITY-DATED-PATH-EXCLUDED-RULE).
Подготовленный контекст. Модуль печатает prepare(): по legalTime
дела один раз на исполнение строит активное множество рёбер PRIO_ACTIVE
(и NORM_PRIO_ACTIVE) из недатированных пар и датированных с окном
[start, end), покрывающим дату; defeat и эффекты полномочий читают его.
saturate() начинается с prepare(), так что раннер и API готовят контекст
сами. Это первый шаг рычага Astra (аналог prepared.program_view оракула):
ключ контекста сегодня — дата права, дальше — выбор прочтений и значения
параметров A3.
Условный терм §56 и вычисляемый аргумент атома тела (DECISION-0270)
Возможности и версия. term:if (условный терм) и term:body
(вычисляемый аргумент атома тела: binary, call, if). Любая — план
law-backend-plan/0.17 модели L1 0.9 с механикой ошибок значения; планы
без них байтово прежние.
if. {k: "if", c, t, e}, условие — bool, cmp, and, or
(values.is_data_condition); статусный тест в условии — отказ плана. Ветви
одного статического вида, иначе отказ. Эмиттер печатает ленивую ветвь
(тернарный оператор, условное выражение Python, замыкание Go).
Вычисляемый аргумент. Фильтр атома с pre: значение считается на уровне
атома ДО открытия его цикла (solver.solve), тип обязан совпасть с типом
слота статически, как у константы тела; при err — try/catch с кодом по
подстановке и issue правила после прохода, как у гарда. Генератор с таким
аргументом берётся, лишь когда переменные аргумента связаны (pick);
полностью связанный литерал — проверка статуса по ключу с тем же
перехватом. Внутри comprehension агрегата ошибка аргумента — отказ плана.
Обход E-0105 в раннере не заземляет конъюнкт с вычисляемым аргументом.
Функции §46, параметры A3, let и match §55.1 (DECISION-0273)
Возможности и версия. function (вызов функции пакета в терме
правила), param:a3 (параметр-датасет A3 в вычисляемом терме), term:let,
term:match. Любая — план law-backend-plan/0.18 модели L1 0.9 с
механикой ошибок значения; пакет, чьи функции читает только вопрос term
(T071), получает план прежней модели версии 0.18 с полем functions.
Планы без всего этого байтово прежние. build_plan добирает возможности до
неподвижной точки: параметр или функция внутри вычисляемого аргумента тела
видны только проходу с term:body.
Функции. functions: [{name, id, params, paramTypes, returns, returnType, body, fallible?}], тело — терм над {k: "fvar", i}, вызов —
{k: "fcall", fn, args}. Эмиттер печатает f_<name> по позиционным
параметрам и таблицу FUNCTIONS для раннера (вопросы term/collect:
арность и виды аргументов — TYPE_ERROR оракула, вид результата —
объявленный). Статически: арность, типы аргументов против параметров, тип
тела против объявленного, рекурсия — отказ плана (у оракула — TYPE_ERROR
и NON_EXECUTABLE_FUNCTION_RECURSION при исполнении). Ошибка значения в
теле — фоллибельность вызова, коды по подстановкам как у 0252; виды
операндов в теле печатаются всегда.
Параметры A3. a3Params: [{id, type, windows: [[start, end, term]]}]
— план разбирает тело датасета (a3.lower_parameter) структурно: цепочка
if по окнам дат, вызов функции строки, Result/Ok [литерал], хвост
MissingParameterValue; иная форма, ось Instant, тип строки не равный
типу значения — отказ. Терм {k: "a3", id}; prepare() (подготовленный
контекст 0269) выбирает окно по legalTime один раз на дело, разрыв —
TermError("MISSING_PARAMETER_VALUE") по подстановке, issue правила,
вывода нет; обход E-0105 код пропускает — NEITHER/COMPUTED, как у оракула
(молчание права). Параметр читается вызовом над const_ref
(round(MRP, 0, "HALF_UP"), как в корпусе), в гарде и в аргументе атома
(pre/err). Голый const_ref параметра в голове или атоме — у оракула
позиция идентичности с отложенным вычислением при чтении связанной
переменной; в срезе это названный отказ плана (29 пакетов корпуса).
Параметр в вопросе term — отказ раннера.
let и match. {k: "let", i, v, b} с переменной {k: "lvar", i}
печатается немедленно вызываемой функцией; тип значения обязан совпасть с
объявленным. {k: "match", s, arms: [{m, v}], x?: false} — только над
перечислением, образцы — вариант без полей (идентичность члена, E-0067) и
_; ветви одного вида; печать — цепочка eq по порядку ветвей, хвост —
TermError("NON_EXHAUSTIVE_MATCH") (статус NON_EXECUTABLE); неполный
match фоллибелен, полный по членам — нет. Образцы с полями, bind,
value — отказ. Таблица статусов раннера дополнена кодами оракула
(NON_EXHAUSTIVE_MATCH, NON_EXECUTABLE_FUNCTION_RECURSION, UNKNOWN_FUNCTION,
OPAQUE_NON_EXECUTABLE → NON_EXECUTABLE, RESOURCE_LIMIT).
Канал суждения §47.3 (DECISION-0274)
Возможность и версия. judgment — программа объявляет отношение
суждения (symbol_decl relationKind judgment, external_decl канала с
органом и формой запроса). План law-backend-plan/0.19; модель не меняется
(L0 остаётся L0): план несёт judgments (орган, requestSchema),
backchain с силой правил и гардами (у L0 — впервые), backchainConsts.
Обход — в рантайме цели, один код для раннера и публичного API: порт
whynot._collect_judgments и соседей над готовым состоянием модели. От
цели без опоры — правила с унифицируемой головой, конъюнкты размечаются под
подстановкой цели (пара опор §62; несвязанная переменная — UNDETERMINED);
правило с заведомо невыполненным конъюнктом мертво (E-0101, кроме
refuted-теста над самим отношением при NEITHER), поражаемое правило, чей
вывод поразил бы сработавший дефитер без приоритета над ним, мертво
(E-0103 — по применениям страт APPLIED), дефитер стоящего вывода жив,
лишь если способен его снять (E-0100 — опоры §107.1 битами); неопределённый
судейский конъюнкт — запрос, прочий — вглубь по паре (атом, полярность)
(E-0111); судейский конъюнкт с несвязанными переменными перечисляется по
активному домену (аргументы всех атомов таблиц в порядке §208, кап 8 ДО
фильтра по NEITHER, DECISION-0036 (б)). Носители кроме тела: valid_when
полномочия при осуществлении (E-0100), кроме эффекта, запертого иммунитетом
(E-0120, карта BLOCKED_IMMUNITY из материализации — она же больше не
выпускает POWER_INVALID_EXERCISE при судье), condition цели обязанности
в вопросе positions. Гард в обходе — мини-вычислитель рантайма над
литералами §53 (переменные, литералы, константы §54, арифметика §58); иной
терм — UNDETERMINED (правило живо, как у оракула при исключении). Лестница
§175: конфликт эффектов, затем судья, затем ошибка терма E-0105.
Ответ судьи §47.3.1. Утверждение с объектом judgment принимается при
совпадении органа с декларацией и формы payload с requestSchema
(виды _TYPE_KINDS); иначе issue JUDGMENT_AUTHORITY_MISMATCH /
JUDGMENT_PAYLOAD_MISMATCH и никакой опоры. Ворота сверяют
judgmentRequests с голденом кроме proof; Answer L1-API несёт
evaluationStatus и judgmentRequests.
Редакции и мир импортов (DECISION-0236)
Жизненный цикл редакции §31 не доходит до эмиттеров: план считает
применимость редакции во всех точках излома её событий (порт
applicability.edition_state) и сворачивает в окна [start, end); окно
правила — пересечение effective с объединением окон датирующих редакций
(достаточно одной применимой). Якорь, не разрешающийся в датированную
редакцию, и граница не дневной гранулярности узел не датируют; пустое окно —
узел в excluded; несколько окон — названный отказ. Датированный факт —
правило с окном над таблицей always с одной строкой.
Мир импортов: build_plan(ir, world), где world — CLIR зависимостей
(замыкание). world_index(ROOT) индексирует снимки по имени пакета,
resolve_world(ir, index, extra) строит замыкание; deliver.py --dep FILE
подаёт зависимость явно, остальное ищется по снимкам; у вектора мир —
producer.ir.json рядом. Узлы с занятым StableId и тем же contentHash
пропускаются (копии фактов у потребителя); имя таблицы при коллизии
локальных имён получает префикс пространства имён. Вопросы API — только у
корня.
Виды вопросов раннера
Вопрос приходит с делом, и план его не видит: вид вопроса — свойство раннера.
Дескриптор цели объявляет QUERY_KINDS; ворота исполняют вектор только
тогда, когда его вид поддержан ВСЕМИ активными целями. ts, py, go
исполняют truth, term и collect (DECISION-0234): comprehension §52.1 по
установленным атомам таблиц с гардами, элемент — ячейка или литерал,
distinct — множество по каноническим байтам, порядок элементов —
канонические байты §208; агрегаты count, sum, min, max §59, пустая
коллекция без options.empty — названный отказ EMPTY_AGGREGATE; only §51
отвечает сам: пусто — TermError EMPTY_AGGREGATE, два различных значения
(канонические байты) — TermError CARDINALITY_CONFLICT, оба со статусом
RUNTIME_ERROR, политика у only — TermError TYPE_ERROR; политика
не-value либо чужого вида над пустой коллекцией — TermError TYPE_ERROR
(errata E-0195, вид элемента — из variable.type.name comprehension);
арифметика §58 и функции рантайма над результатом. Вид результата раннер
выводит статически теми же таблицами §58, что план: у оракула вид — часть
значения. Запись, поданная делом и сущностью, и Text, — названный отказ:
рантайм их не различает. Ответ term — resultKind: DATA с литерал-термом
§53, collect — COLLECTION со списком; ворота сравнивают значение с
голденом оракульским каноном (lawref.canon), а не сериализатором цели.
С DECISION-0252 и DECISION-0256 арифметику вопроса term раннер исполняет
рантаймом arith над точными видами значений, а не таблицей видов: ошибка
значения — ответ без значения со статусом по таблице queries.query_calc
(TYPE_ERROR для TYPE_ERROR, CURRENCY_MISMATCH, DIMENSION_MISMATCH,
DATE_INSTANT_MISMATCH, иначе RUNTIME_ERROR). Сравнение lt…ne в вопросе —
values.binary: валюта, единица, затем вид (TYPE_ERROR); числовые виды и
Date, ответ — Boolean. Литерал Rational операнда вычисляется ratTerm
(сократимая запись нормализуется, ERR-E0005); записи дела и вопроса truth
— только канонические, rat. С DECISION-0259 round и div_round в вопросе
исполняют roundMode и divRound с точными видами аргументов: ошибка политики
— ответ без значения со статусом той же таблицы (CURRENCY_MISMATCH —
TYPE_ERROR, DIVISION_BY_ZERO — RUNTIME_ERROR); пара вне E-0036/E-0170,
Rational в аргументе, точность не числом и режим не Text — названный отказ.
Контракт рантайма
Операции ниже ведут себя одинаково во всех целях; всё остальное печатает
эмиттер. Состав контракта цели объявлен в runtime_cert.py: 19 базовых
операций (BASELINE_OPERATIONS) обязательны для каждой цели и достаточны
для плана 0.7; ещё 13 (EXTENSION_OPERATIONS: arith, counter,
divRound, monthStart, monthEnd, qty, rat, ratTerm, roundMode,
instant, hoursBetween, minutesBetween, addDuration) — операции видов
значений и функций поздних планов: Rational, Quantity, округление §50,
границы месяца, Instant. Полный набор сегодня несут ts, py, go; новый
целевой язык начинает с базового. Каждый громкий отказ ниже — значение одного
названного типа Refused (класс исключения в Python и TypeScript, тип
panic в Go); раннер узнаёт только его. Любая другая ошибка — крах.
| функция | обязательство |
|---|---|
dec(строка) |
точное десятичное значение произвольной длины (канонической записи плана; сырое поле литерала читают lit* — см. «Сырое поле литерала §208») |
money(строка, валюта) |
то же плюс валюта |
add, sub, min, max |
точно, масштаб — больший из двух; виды и валюты обязаны совпасть, иначе громкий отказ |
mul(a, b) |
точное произведение; масштаб результата — сумма масштабов; два Money — громкий отказ |
div(a, b) |
точное частное при 10-гладком знаменателе, наименьший точный масштаб; иначе громкий отказ (Money — INEXACT_DIVISION); ноль — громкий отказ |
mod(a, b) |
евклидов остаток над целыми; ноль и нецелые — громкий отказ |
abs, pow |
вид сохраняется; pow только над целыми с пределами показателя и значения |
round(значение, разрядов, режим) |
только названный режим; HALF_UP округляет ОТ НУЛЯ; над Integer — тождество |
cmp(a, op, b) |
порядок; разные валюты и сравнение денег с безразмерным — громкий отказ |
eq(a, b) |
равенство значений, а не записей: 2469 и 2469.00 равны |
key(строка) |
канонический ключ строки таблицы для дедупликации; виды различимы: сущность, дата, член перечисления, деньги, число |
date(строка) |
календарный день §2.15 в канонической записи ISO; порядок и равенство — по дню, с другими видами не сравнивается (§57) |
sym(идентификатор) |
член перечисления §38 или ссылка без объявления: равенство по идентичности, порядок не определён (§57) |
Boolean в eq, cmp, key |
DECISION-0266: значение языка (boolean); eq — только Boolean того же значения; cmp — eq/ne, иначе громкий отказ «§57: вид Boolean не упорядочен»; ключ b:true/b:false, отличный от числа и текста; в арифметике — громкий отказ видов |
month_start(дата), month_end(дата) |
§84.2 (DECISION-0267): первое и последнее число месяца в канонической записи, високосность по григорианскому правилу; не Date, не ISO-дата, несуществующий день — TermError TYPE_ERROR; политика §86 и снимок §85 не читаются |
setLegalTime / legalTime |
правовое время дела; без него окна §31 не вычисляются |
rat(строка) |
Rational §35 (DECISION-0252): только каноническая запись n/d §168.1 — несократимая, знаменатель положителен, ноль 0/1; части — по лексике §208 (errata E-0203); иная запись — громкий отказ, а не сокращение; целые произвольной длины |
arith(op, a, b, lk, rk) |
план 0.12: add, sub, mul, div, mod по таблице §58 values.binary над статическими видами операндов i Integer, d Decimal, m Money, r Rational, n Decimal либо Rational по классу значения; вид, расходящийся со значением, — громкий отказ. Integer/Integer и Rational/Rational — Rational (целое частное остаётся Rational); Decimal/Decimal, Money/Money одной валюты — Decimal при 10-гладком частном, иначе Rational; Money*Rational в обоих порядках — Money, 10-гладкость после сокращения; ошибка значения — TermError с кодом оракула: DIVISION_BY_ZERO, INEXACT_DIVISION, CURRENCY_MISMATCH, TYPE_ERROR (Rational с Decimal или Money, Rational/Integer, mod не над целыми) |
ratTerm(строка) |
литерал Rational операнда вопроса term — разбор оракула: n/d с целыми частями по лексике §208 (errata E-0203: [+-]?[0-9]+, без пробела, _ и не-ASCII цифры), сократимая запись и знак в знаменателе нормализуются; не n/d — TermError TYPE_ERROR, знаменатель 0 — DIVISION_BY_ZERO (ERR-E0005; каноничность §168.1 — у записей дела и вопроса truth, там rat) |
qty(строка, единица) |
Quantity §49 v1 (DECISION-0256): точное десятичное значение и тег единицы — байты записи, без реестра единиц и алиасов; отличен от Money |
arith над q |
вид q — Quantity: Q±Q, сравнение, min/max разных тегов — TermError DIMENSION_MISMATCH, Quantity с иным видом — TYPE_ERROR; Integer/Decimal × Q — Q того же тега; Q×Q, Q с Money или Rational — TYPE_ERROR; Q/Decimal — Q, неточно INEXACT_DIVISION, ноль DIVISION_BY_ZERO; Q/Q одного тега — Decimal либо Rational по значению, разных тегов — TYPE_ERROR раньше нуля; Q/Integer, Decimal/Q, mod — TYPE_ERROR |
Quantity в add, sub, min, max, abs, round, cmp, eq, key |
тег сохраняется; разные теги в add/sub/min/max/cmp — DIMENSION_MISMATCH, Quantity с иным видом — TYPE_ERROR, в eq — ложь; ключ q:<тег>:<число> с экранированием тега, отличный от денег с тем же тегом |
counter(величина, функция) |
счётчик-связыватель §86.1: Quantity с единицей, допустимой функции (add_business_days — дневные, add_calendar_period — календарные, add_legal_term — все пять), целый; иначе TermError TYPE_ERROR; возвращает число и единицу; знак не проверяет (отрицательный — DEADLINE_POLICY_INVALID операции) |
add_legal_term(дата, число, единица) |
§86.1: business_day/calendar_day — add_business_days, прочие — add_calendar_period |
roundMode(значение, точность, режим, vk, pk) |
план 0.14 (DECISION-0259): round §50 с проверкой политики в порядке оракула — вид значения (n с Rational — TermError TYPE_ERROR), точность Integer либо целый Decimal (pk; дробная или отрицательная — TYPE_ERROR), режим из семи (иначе TYPE_ERROR); округление — порт _round_fraction на целых; Integer — тождество; точность не короче дробной части — значение то же, без дополнения нулями |
divRound(делимое, делитель, точность, режим, ak, bk, pk) |
план 0.14: пары m/d, q/d, d/d, m/m, иначе TYPE_ERROR → у m/m разные валюты CURRENCY_MISMATCH → ноль DIVISION_BY_ZERO → точность целая 0..34, иначе TYPE_ERROR → режим; частное точное, округление всегда, масштаб результата — точность; m/d — Money той же валюты, q/d — Quantity той же единицы, m/m — Decimal без тега |
Rational в add, sub, min, max, abs, cmp, eq, key |
с Rational — по значению; Rational с иным видом в add/sub/min/max/cmp — TermError TYPE_ERROR, в eq — ложь; ключ r:n/d, отличный от числа и денег: 2/1 и Decimal 2 — разные ключи |
instant(строка) |
Instant §2.15 (W2, часть 2): запись хранится как подана и служит идентичностью атома (E-0214); eq и cmp — по моменту (E-0048): 12:00:00+05:00 и 07:00:00Z равны; ASCII-григорианская дата и обязательное корректное смещение; дробь любой длины сравнивается точно; невалидная запись — TYPE_ERROR, с Date не сравнивается (§57) |
hoursBetween, minutesBetween, addDuration |
§84.1: полных часов или минут со знаком, дробь к нулю; addDuration(мгновение, число, единица) — секунды, минуты, часы или сутки, ответ канонично в UTC без дробных секунд; запись без смещения отвергается admission |
Сырое поле литерала — грамматика §208, а не средства языка цели
Errata E-0197, E-0202 и E-0203 (20.09.2026) закрыли у обоих оценщиков один и
тот же дефект: сырое поле value литерала §53 читалось конструктором РОДНОГО
языка, и «так делает мой язык» становилось нормой. У целей генератора дефект
был тот же и разошёлся сильнее, потому что языков три, а не два.
Правило одно. Поле литерала читается по грамматике §208, названной явно, а
не тем, что примет int(), Decimal(), Number(), parseFloat, strconv
или math/big. Носитель поля проверяется ПЕРВЫМ (rawLit / raw_lit /
rawOfMessage, rawOfValue), и только потом — запись:
| вид | канон §208 | иная форма |
|---|---|---|
Text, Date, Instant, Rational, currency, unit |
JSON-строка | TermError TYPE_ERROR |
Integer |
целое JSON-число знакового 64-битного диапазона | TermError TYPE_ERROR |
Decimal, Money, Quantity |
JSON-строка по лексике ниже либо целое JSON-число | TermError TYPE_ERROR |
Boolean |
JSON-булево | громкий отказ (DECISION-0266) |
Natural |
неотрицательное целое JSON-число | громкий отказ (DECISION-0266) |
Две лексики — дословный порт lawref/values.py (_DECIMAL_LEXIS,
_FRACTION_PART_LEXIS) и law-eval/src/values/literal.rs:
десятичное: ^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$
часть дроби: ^[+-]?[0-9]+$
Форма УЗКАЯ по решению errata E-0203, и это не придирка к алфавиту: сужены
ровно пробельный символ, _, не-ASCII цифра и Infinity/NaN — четыре оси,
у которых радиус по всему дереву нулевой. Экспонента (1e2 → 100),
ведущие и хвостовые нули (1.50 → 1.5), знак +, .5, 5. и сократимая
дробь (2/4 → 1/2) остаются законной записью входа и нормализуются.
Ужесточать сверх этого нельзя: ERR-E0203-DECIMAL-EXPONENT,
-DECIMAL-CANON-FORMS и -RATIONAL-REDUCIBLE стоят в векторах именно
границей, без которой «запись судится» не отличалось бы от «нормализация
отменена».
В Python якорь обязан быть \Z, а не $: Python-овый $ пропускает
хвостовой перевод строки, и "1.5\n" прошёл бы. В JavaScript без флага m и
в RE2 без (?m) $ уже строг.
Граница i64 у TypeScript. JSON.parse сводит число к double, и целое
знакового 64-битного диапазона теряет знаки НА ЧТЕНИИ: на
ERR-E0202-CANON-NUMBER-I64-MAX в ответ уходило 9223372036854776000 — не
меньший ответ, а другой, то есть ровно то, что DECISION-0188 запрещает. Отказа
здесь достаточно не было: py и go это целое несут точно, а отказ одной цели
при ответе двух других ворота читают расхождением. Радиус перехода мерился и
оказался мал: Dec.u в runtime.ts УЖЕ bigint, и печать результата уже идёт
носителем {int: "<цифры>"}. Поэтому чинится только чтение — RT.parseJson
разбирает текст, пропуская строки отдельной ветвью, и заменяет целое вне
±2^53 тем же носителем {int: "<цифры>"}, который читает и харнесс API.
Number.MAX_SAFE_INTEGER нигде не становится нормой: границей нормы остаётся
i64 §208, а 2^53 — лишь порог, за которым нужен точный носитель.
JSON-число вне канона §208 (float либо целое вне i64) оракул и движок
отвергают ОТКАЗОМ СОБРАТЬ ДОКУМЕНТ — error-объектом §172, а не issue. У
порождённого модуля такого канала нет: профиль core-executable документа не
строит. Поэтому тот же вход даёт названный отказ раннера одним текстом у всех
целей: JSON-число вне канона §208 (только целое знакового 64-битного диапазона) вне среза раннера.
Текст issue модуль не печатает, и контракт здесь — КОД. В ответе раннера
любого вида (раздел «Контракт раннера») issues — список кодов; ворота
сверяют коды (BACKEND_ISSUES), а не формулировки. Дословные
сообщения оракула (term: Integer ожидает целое JSON-число, получено {"a":1})
стоят в векторах и в errata, а у модуля тот же случай — код TYPE_ERROR.
Долг, названный числами. (1) Литералы ПРОГРАММЫ (ir.json) читает
plan.py, и он остался permissive: 570 литералов Integer в векторах
записаны JSON-строкой ("11"), тогда как оракул после E-0197 даёт на такой
записи TYPE_ERROR. Сегодня это ничего не ломает — ни одно из этих правил в
своём векторе не вычисляется, — но норма у плана и у раннера разная, и это
записано, а не забыто. (2) Сокращение дроби в plan.py (ветвь RAT)
существует потому, что канон ядра дробь НЕ сокращает, а рантайм цели требует
канона §168.1; владелец решил 20.09.2026, что канон ядра сокращать начнёт —
отдельной errata. После той errata костыль подлежит снятию тем же
изменением, и до неё он не трогается.
Сертификация рантайма
Контракт выше исполняем: runtime-cert.json — фикстура вызовов и ожиданий,
записанных ИЗ этого раздела, а не снятых с реализации. Сравнение целей между
собой общую ошибку не находит: коллизия ключа ["a|e:b","c"] /
["a","b|e:c"] жила во всех трёх рантаймах одинаково и теряла второй факт.
Харнесс каждой цели (targets/<цель>/cert.*) исполняет фикстуру и печатает
результат, ожиданий он не читает; ворота сверяют каждый случай с ожиданием
до исполнения векторов. Отображение в фикстуре — с явным масштабом
(2.00 KZT, не 2 KZT), поэтому она держит и масштаб результата, а не
только его значение. Литералы: {dec}, {money, cur}, {text}, {date},
{sym}, {row} — у всех харнессов; {rat}, {qty, unit}, {bool},
{instant} — только у харнессов полного контракта (COMMON_LITERAL_TAGS и
EXTENSION_LITERAL_TAGS в runtime_cert.py); ожидание — строка, булево, null,
{refused: текст} либо {termError: код} (ошибка значения плана 0.12,
DECISION-0252); Rational отображается n/d. Новый случай
контракта — строка фикстуры, новая цель — харнесс на 60–120 строк.
Ключ дедупликации экранирует разделитель и экран внутри текста (| → \|,
\ → \\): длина в префиксе была бы разной у языков (байты, code points,
UTF-16), экранирование — нет.
Контракт раннера
Раннер принимает case.json и query.json и передаёт их единому входу
evaluate (у ts, py, go; раздел «Единый вход и библиотека»); у прочих
целей раннер сам подаёт факты дела в таблицы, насыщает и отвечает. Три исхода
различаются протоколом выхода, а не одним ненулевым кодом:
| исход | код | stdout |
|---|---|---|
| ответ | 0 | JSON по виду вопроса, таблица ниже |
| названный отказ среза | 3 | {"refused": текст} |
| крах | любой другой | что угодно; ворота валят |
Форма ответа зависит от вида вопроса (QUERY_KINDS дескриптора). value —
литерал-терм §53, issues — список кодов:
| вид | ответ |
|---|---|
truth у ts, py, go |
{queryId, truthStatus, evaluationStatus, judgmentRequests, issues} |
truth у остальных целей |
{queryId, truthStatus, evaluationStatus, issues} |
term |
{queryId, resultKind: "DATA", value, evaluationStatus, issues}; при ошибке значения value нет, evaluationStatus — TYPE_ERROR либо RUNTIME_ERROR |
collect |
{queryId, resultKind: "COLLECTION", value, evaluationStatus, issues} |
positions |
именованный отказ POSITIONS_UNAVAILABLE до W6 |
Текст отказа обязан совпадать между целями побайтово; отказ одной цели при ответе другой — расхождение. Отказы, зависящие от данных дела, закономерно возникают при исполнении, но их перечень общий; основные:
| текст | когда |
|---|---|
аргумент вне среза раннера: <kind> |
аргумент дела не value, не entity_ref и не const_ref — например record (конструктор события) или interval |
аргумент вне среза раннера: <URN типа> |
значение типа, которого раннер не знает |
§113: отрицательный факт вне L0-среза |
утверждение дела с polarity ≠ positive у модели L0; модель L1 принимает negative |
вид запроса вне среза раннера: <kind> |
вид вопроса вне QUERY_KINDS цели: у ts, py, go — не из truth, term, collect; у остальных целей — любой, кроме truth |
POSITIONS_UNAVAILABLE |
positions временно снят в R до переноса рангов norm runtime в W6; отказ одинаков у библиотеки и раннера трёх целей |
ошибка значения вне среза раннера: <код> |
ошибка значения вне вопроса term и вне правил модели, например в гарде comprehension вопроса |
| отказы рантайма из таблицы выше | валюты, режим округления, порядок на Text, Date с другим видом, порядок над перечислением, legalTime |
Типы аргументов дела сверяются с params таблицы до преобразования
значений — зеркало check_argument_types оракула (§189/§48, errata E-0046):
несогласованное по арности или типу утверждение не принимается, в issues
ответа встаёт TYPE_ERROR; entity_ref типа не несёт и не проверяется;
предикат без сигнатуры принимается и никем не читается. До этой проверки на
ERR-E0046-CASE-ARG-TYPE Python и Go отвечали TRUE_ONLY против голдена
NEITHER, а ворота этого не видели: TypeScript отказывал на Integer первым,
и вектор шёл в «отказ рантайма».
Коды issues сверяются между целями целиком, а с голденом — по кодам,
которые срез порождает сам: набор BACKEND_ISSUES ворот, 18 кодов —
TYPE_ERROR, KEY_CONFLICT и коды ошибок значения §58, агрегатов §59,
календаря §85/§86, эффектов полномочий §127–§128 и ответа судьи §47.3.1.
Без сверки с голденом KEY_CONFLICT был бы невидим воротам: он не меняет
статус, и модуль, молча не считающий ключи, совпадал бы с голденом по
статусу и с соседями по пустому списку. Коды вне набора с голденом не
сверяются, только между целями.
Аргументы запроса сверяются с той же сигнатурой, но без TYPE_ERROR:
ключ ground-атома у оракула (§208) включает тип значения, поэтому запрос с
Integer 1 к утверждению Decimal 1 атома не находит и отвечает NEITHER
без issue, а разная запись одного Decimal (0.5 и 0.50) — один атом.
Рантайм сравнивает числа по величине и без проверки отвечал бы TRUE_ONLY.
Векторы — LAY-L0-QUERY-ARG-TYPE и LAY-L0-QUERY-ARG-SCALE; несогласованный
по арности или типу запрос просто не совпадает ни с одной строкой.
Типы головы правила проверяются планом статически (E-0077): тип слота
тела, литерала, константы или результата mul/round обязан совпасть с
объявленным типом параметра головы; сущности не проверяются, как у оракула.
Оракул отвергает такой вывод при исполнении, рантайм среза положил бы Integer
в Decimal-слот и ответил по величине. Вектора среза на это нет: исходник с
такой головой отвергает уже lawc check (LDC-E2104), а обязательство
оракула держат ERR-E0077-* над Quantity, которые план отвергает раньше.
Запуск
python3 verify/ci/gates/backends/check_backends.py # шаг 73/73 полного конвейера
python3 verify/ci/gates/backends/check_backends.py --require ts,py,go # без тулчейна — отказ
python3 verify/ci/gates/backends/check_backends.py --keep /tmp/backends # оставить проекты
python3 verify/ci/gates/backends/check_backends.py --write-manifest # закрепить исходы
python3 engines/backends/targets/go/emit.py <ir.json> model.go # одна цель вручную
Цель Python исполняется всегда: без неё ворота сообщали бы «зелено», не
исполнив ни одного бэкенда. TypeScript требует node и tsc с типами Node:
собственный проект тулчейна targets/ts/package.json (npm ci там), запасной
путь — apps/constructor/node_modules. Go требует go в PATH. Отсутствие
тулчейна НАЗЫВАЕТСЯ в отчёте, а не молчит; --require делает его отказом.
Ворота идут шагом рабочего профиля (run_all.sh → work_profile.py) на
каждом прогоне с обязательными ts,py,go (py при --python-only): они
читают только conformance-векторы, корпус им не нужен, и DECISION-0184 это
не нарушает. Workflow профиля ставит node, npm ci и go явно. В полном
конвейере — шаг 73/73.
Ворота исполняют каждый вектор ВСЕМИ доступными целями и различают три
исхода по протоколу раннера. Крах любой цели валит ворота. Исход каждого
L0-вектора закреплён в verify/ci/data/backends-vectors.json: match,
plan: <причина>, query: <вид>, golden: результатов <n>,
runtime: <текст отказа>. Закреплённый исход обязан повториться, закреплённый
вектор — существовать, незакреплённое совпадение — ошибка регистрации.
Одно число исполненных векторов позволило бы потерять старый случай и
компенсировать его новым, поэтому пол MIN_CHECKED остался второй защитой.
Поставка порождённого модуля
./law dev backend corpus/clir/kz-grammar-tasymal.lawir.json --target ts --target go --out DIR
deliver.py печатает пакет в DIR/<цель>/: model.*, runtime.*,
runner.*, у ts, py, go ещё api.*, evaluate.* и общую часть API (у Go
ещё go.mod), plan.json и паспорт law-backend.json
формата law.backend-delivery/1: версия плана, цель, паспорт пакета из
CLIR, семантический хэш §209 самого CLIR (в снимках поле semanticHash
бывает нулевым, поэтому считается здесь), профиль и SHA-256 каждого файла.
Паспорт связывает модуль с каноном. Отказ плана — отказ поставки с
названной причиной и кодом 2: «меньше пакета» печатать нельзя. Ворота
печатают проекты той же функцией emit_project, так что проверяется ровно
то, что уезжает. Устанавливаемый пакет — следующий раздел.
Устанавливаемые пакеты (DECISION-0423 §2.7)
arxo-codegen-package root.lawir.json --target py --name NAME --version 1.0.0 --out DIR
arxo-codegen-package root.lawir.json --target ts --name @scope/name --version 1.0.0 --out DIR
arxo-codegen-package root.lawir.json --target go --name NAME --version 1.0.0 \
--module example.com/org/name --out DIR
package.py печатает библиотеку тем же эмиттером, что и поставка, и меняет
только раскладку и импорты:
| цель | раскладка |
|---|---|
| Python | pyproject.toml, src/<импорт>/__init__.py (реэкспорт api и info()), api.py, _internal/ (рантайм, модель, evaluate, общая часть API — относительные импорты), py.typed, api-map.json данными пакета |
| TypeScript | package.json (exports, types, files, engines), src/index.ts, src/api.ts, src/internal/, собранный dist/ с .d.ts — собственным тулчейном цели; Node не нужен рантайму (порядок UTF-8 без Buffer) |
| Go | go.mod с путём --module, код в корневом package <имя> (приватность — регистром имён), EvaluateJSON, Info(), команда cmd/<имя>-eval с протоколом раннера |
В каждом пакете — README.md с исполняемым примером (факты по входам первого
вопроса и сам вопрос), api-map.json формата law.codegen-api-map/0.1
(функция → вопрос или вход → StableId → производящие правила → якоря
источника) и паспорт law-backend.json: поля поставки плюс distribution
(имя, версия, у Go — модуль и пакет), generator (версия arxo-codegen),
coreKit (SHA-256 манифеста комплекта ядра), capabilities плана и api
(abi: law.codegen-api/1, valueFormat: law.codegen-value/1) — провенанс
артефакта, а не доказательство вычисления; тот же текст вшит в пакет и
отдаётся info() / Info().
Значения между канонами. to_value/from_value (Python),
toValue/fromValue (TypeScript), ToValue/FromValue (Go): текст
law.codegen-value/1 — канонический JSON литерал-терма §53 (ключи по
порядку, без пробелов, Integer — числом, без экранирования HTML). Один терм
даёт одни байты во всех трёх языках, поэтому значение из модуля одного канона
передаётся в модуль другого или в сервис без знания языка. Раннер и план ворот в пакет не входят. Минимальные
версии тулчейна — константы целей TOOLCHAIN_MIN (Python 3.13, Node 20,
Go 1.25), равные версиям проверок CI; тест сверяет их с
.github/workflows/candidate.yml. Имя пакета — параметр; для канонов,
которые публикует Arxo, — семья -lib: @arxo/canon-<имя>-lib,
arxo-canon-<имя>-lib, github.com/arxohq/canon-<имя>-lib (выбор владельца
28.09.2026); @arxo/canon-<имя> без суффикса — пакет самого канона
(DECISION-0349 §8).
Проверка. check_packages.py (arxo-codegen-check-packages, шаг приёмки
ci/verify.py): для API-пакетов комплекта печатает пакет каждой цели и ставит
его так, как получит потребитель, — Python каталогом из src/, TypeScript
тарболом npm pack без сети, Go модулем-потребителем с replace; задания
check_api исполняются через опубликованную поверхность пакета и обязаны
совпасть с плоским API Python; пример README обязан исполниться; канарейка
портит статус и issues в установленном Python-пакете — расхождение обязано
найтись.
Обзор корпуса и первый потребитель
./law dev backend-survey --report FILE проходит все снимки CLIR (с
миром импортов по снимкам; третий обзор — SURVEY-2026-09-14-editions.ru.md,
план 0.7: 778 снимков, строится у 60; четвёртый —
SURVEY-2026-09-14-l1.ru.md, план 0.8: строится у 106 — L0 те же 60, L1
46, из них kz.* 26; пятый — SURVEY-2026-09-14-closure-aggregates.ru.md,
план 0.9: 780 снимков, строится у 123, из них с aggregate 10, с closure 9;
шестой — SURVEY-2026-09-15-norms.ru.md, план 0.10: 802 снимка, строится у
151, с norm 24, из них kz.* 12)
(corpus/clir/ и собственные снимки packs/) обзорным режимом плана,
который собирает ВСЕ отказы пакета, а не первый. Отчёт 09.09.2026 —
SURVEY-2026-09-09.ru.md, второй (план 0.5, 14.09.2026) —
SURVEY-2026-09-14.ru.md: 771 снимок, план строится у 50 против 31, из
19 новых пакетов 8 — словари vocab.* с ключами, остальные — грамматика,
фикх и три акта КЗ с константами в теле. Первый же обзор дал рычаг: узел publication
(провенанс §27.3, из семантического хэша исключён по §28) отвергал 621
пакет; после его пропуска план строится у 31 пакета вместо 5. Два следующих
рычага обзора оказались не тем, чем читались: «константа не найдена»
(193 пакета) почти целиком была членами перечислений и параметрами A3, а
131 «несовпадение типа головы» — ложным срабатыванием статической
типизации, приписывавшей Money любой операции. После плана 0.3 (Date,
константы, перечисления) принятых по-прежнему 31: у пакетов с датами и
перечислениями всегда есть вторая причина. Дальше по пакетам:
defeasible/defeater (367), объявления вне среза (451: norm_template,
priority_rule, closure_policy, external_decl), типы (362: Quantity,
Event, Rational, Instant), функции (179) — всё это семантика.
./law dev backend-consumer <пакет> поставляет пакет корпуса, понижает его
собственные .lawtest компилятором и спрашивает поставленный модуль.
Наборы берутся обнаружением ворот .lawtest (corpus/lawtests/discovery.py):
у каждой части свой мир (world, concat) — он же мир плана — и
resolve-контекст §23 для понижения; часть с merge = "concat" или снимками
§47.2 — названный пропуск. Сценарии понижаются через ./law engine lower-test --imports; файл, который не понижается, — ошибка; если дело несёт
отрицательный факт, план строится с возможностью negation. Без имён
пакетов потребитель сверяет все пакеты манифеста
verify/ci/data/backends-consumers.json (число сценариев, исходы, статусы;
пол MIN_CONSUMER_MATCHED), --write-manifest закрепляет названные. Замер
печатается и не закрепляется: страты, правила, пики кандидатов и групп
(STATS модели py, третий аргумент раннера) и время по целям. 14.09.2026
(DECISION-0237 этап 6): kz.corpus.stazh_gossluzhby, kz.grammar.bas_arip,
kz.grammar.kirme_sozder — 144 из 144 на ts,py,go; без дефитеров модуль
меняет 7 ответов, без поражаемых правил — 32. 15.09.2026 (DECISION-0242):
вопрос positions сверяется по result_kind, normative_status,
evaluation_status и наблюдениям position, position_status,
position_count, positions_present (порт lawref.lawtest); concat
наборов входит в мир плана. 19 пакетов с позициями — 825 совпадений из 841
сценария, без норм-правил модуль меняет 79 ответов, без эффектов — 16; пол
MIN_CONSUMER_MATCHED 336 → 1161.
09.09.2026: 24 принятых пакета со сценариями (грамматика казахского,
myco.primety, stacks.sets, разрешения mathlib/isabelle), 300 сценариев,
298 совпали, 2 пропущены как why_not, расхождений и крахов нет. Это и
есть первый потребитель: правила грамматики с сущностями и Text.
Замер 09.09.2026 (план 0.2, протокол исходов)
| исход | штук |
|---|---|
| L0-векторов рассмотрено | 340 |
| отказ плана | 100 |
запрос не truth |
189 |
| голден без результата (фатальная диагностика) | 12 |
| исполнено всеми тремя целями | 39 |
| совпало с голденом и между целями | 36 |
| единогласный отказ рантайма | 3 |
| крах, расхождение между целями, расхождение с голденом | 0 |
| сертификация рантайма | 111 случаев × 3 цели |
Против первого замера (25 / 19 / 6): два вектора ушли из «отказа рантайма»
в совпадение (ERR-E0041, ERR-E0046-CASE-ARG-TYPE — Integer в TypeScript
и проверка типов дела), два — в отказ плана (T151, T155 — параметры
Rational и Instant), один — из совпадения в отказ плана по ключам §45.1
(LAY-L0-KEYS), один крах Go на const_ref стал названным отказом; два
новых вектора запроса (LAY-L0-QUERY-ARG-*) совпали после проверки типов
запроса. Шаг ворот целиком — 12 секунд, включая сертификацию, tsc и
24 сборки go build.
Замер 14.09.2026 (план 0.5, цели ts,py,go): рассмотрено 385, отказ плана
127, запрос не truth 201, голден без результата 14, исполнено 43, совпало
40, отказ рантайма 3, расхождений и крахов 0. Из отказа плана в совпадение
ушли LAY-L0-KEYS (KEY_CONFLICT сверен с голденом) и
ERR-E0052-DECIMAL-CANON (константа в теле); пять ERR-E0165-WILDCARD-*
сменили причину на названный отказ по _ §98, шесть векторов с ключами —
на следующую причину (календарные функции, отрицательный литерал).
Канарейки: сдвиг значения фильтра в порождённом коде даёт NEITHER, эмиттер
с key_conflicts ≡ 0 валит ворота расхождением issues на LAY-L0-KEYS.
Десять целей разом не прогонялись (тяжёлый прогон); семь остальных
эмиттеров и раннеров проверены только пробой версии плана.
Замер 14.09.2026, вечер (план 0.6, DECISION-0234, цели ts,py,go):
рассмотрено 385, план построен и вид поддержан 240, совпало 49, отказ
рантайма 191 (единицы, границы, календарь, Rational — названные отказы),
расхождений и крахов 0. Девять новых совпадений — term и collect.
Поставка kz.grammar.tasymal: api.ts под tsc --strict, api.go под
go build, api.py на сценарии KZ-TAS-01 — TRUE_ONLY с фактом,
NEITHER без, снова TRUE_ONLY: состояние между вызовами не протекает.
Замер 14.09.2026, ночь (план 0.8, DECISION-0237, цели ts,py,go, шаг
ворот 2 мин 36 с): L0 — рассмотрено 385, совпало 56 (было 51, все прежние
целы; в совпадение ушли ERR-E0018-MONOTONE-EVAL, T171, T002,
LAY-L0-NEGATIVE-STRICT-HEAD, …-BOTH), отказ плана 119, отказ рантайма
191; L1 — рассмотрено 44, совпало 24, структурных отказов 3
(LAY-L1-STATUS-CYCLE, T009, ERR-E0099-UNLESS-HEAD-UNBOUND), отказ
плана 17 (агрегаты в гардах 7, прочтения 4, приоритеты 3, квантор,
Rational, поздний производитель); расхождений и крахов 0. API — 48 вопросов
на 5 пакетах; 18 заданий на двух L1-пакетах дополнительно сверены с
оракулом вне ворот — 0 расхождений. MIN_CHECKED 51 → 56,
MIN_CHECKED_L1 = 27, манифест 429 исходов.
Замер 14.09.2026, ночь (план 0.9, DECISION-0239, цели ts,py,go): L0 —
совпало 66 (+10 к 56: closure — LAY-L0-CLOSURE, …-BINARY,
…-EFFECTIVE-IN/OUT, ERR-E0097, ERR-E0113-CLOSURE-TWO-LEVELS; агрегаты —
LAY-L0-AGGREGATE-DERIVED-STRICT, LAY-L0-BODY-AGGREGATE, T164,
ERR-E0112-COMPLETION-HEAD-AGGREGATE), L1 — 31 совпадение и 5 структурных
отказов (+7 T199–T230, остальное — новые векторы E-0172/E-0173 соседней
работы), расхождений и крахов 0; полы 66 и 36, манифест 439.
Замер 15.09.2026 (план 0.10, DECISION-0242, цели ts,py,go, шаг ворот
около 3 мин): L0 — совпало 73, L1 — 31 и 5 структурных отказов, L2 —
совпало 11 (LAY-L2-DUTY, …-MAINTENANCE-SHORT-WINDOW,
…-MAINTENANCE-OUT-OF-DOMAIN, …-CONFLICT-TWO-LIBERTIES-NONE,
…-NORM-BODY-AGGREGATE, T014–T017, T032, T146), отказ плана 101, единогласный
отказ рантайма 1 (LAY-L2-CONFLICT-EXPLICIT-DUTIES, incompatible в
деле), L3 — совпало 9 (LAY-L3-LIBERTY-*, LAY-L3-RECURSION-CLOSURE,
T005, T018, T019, T031, EVT-NO-PROCEDURE-L1-CONSERVATIVITY);
расхождений и крахов 0. T182 сменил причину отказа на конфликт позиций
по ключу §45.1 (K5). Пол MIN_CHECKED_L2 = 20, манифест 744 исхода.
Структурный голден L1 при отказе плана по форме вне среза (условный терм
головы ERR-E0176-DEFEASIBLE-SELF-CYCLE) закрепляется отказом плана;
ошибкой ворот остаётся построенный план и отказ другой структурной
причиной.
Замер 16.09.2026 (план 0.15, DECISION-0266–0268, цели ts,py,go, шаг
ворот около 4 мин без конкуренции): рассмотрено L0 507, L1 94; план построен и
вопрос поддержан у 445; L0 — совпало 225, отказ плана 110, отказ рантайма 151;
L1 — 32 и 5 структурных отказов; L2 — 26; L3 — 9; расхождений и крахов 0.
Манифест перепинован целиком — 913 исходов (292 совпадения): до этого 77
совпадений стояли незакреплёнными (в том числе LAY-L0-RND-* 0259) и 145
исходов изменились с прежних закреплений, большинство — из 0252/0256/0259,
чей перепин откладывался; из 0266–0268 — ERR-E0084-MONTH-* 7 и
ERR-E0165-WILDCARD-* 4 в совпадение, 16 новых векторов (14 совпадений, 2
отказа плана по замыслу). Полы MIN_CHECKED 82 → 225, MIN_CHECKED_L1
36 → 37, MIN_CHECKED_L2 21 → 35. Обзор корпуса — SURVEY-2026-09-16-values.ru.md:
228 из 826, план 0.15 у 7 пакетов; потребители bio.mendel 5/5 и
eu.social_security.coordination 50/50 закреплены.
Замер 16.09.2026, вечер (план 0.16, DECISION-0269, цели ts,py,go):
рассмотрено L0 507, L1 104; план построен и вопрос поддержан у 454; L1 — 41
совпадение и 5 структурных отказов (+9 LAY-L1-PRIORITY-DATED-*, вектор
цикла на отрезке — отказ плана), L0, L2, L3 прежние; расхождений и крахов 0;
манифест 923 исхода, MIN_CHECKED_L1 37 → 46. Обзор корпуса —
SURVEY-2026-09-16-priorities.ru.md: 242 из 826, план 0.16 у 14 пакетов;
потребители — 12 пакетов закреплены (+250 совпадений, MIN_CONSUMER_MATCHED
2181 → 2431), kz.corpus.kacd_svod_pravil с 27 названными отказами
AMBIGUOUS_CALENDAR.
Замер 16.09.2026, поздний вечер (план 0.18, DECISION-0273, цели ts,py,go,
шаг ворот 8 мин 37 с): L0 — совпало 251 (+17: LAY-L0-A3-PARAM-*,
LAY-L0-FN-*, LAY-L0-LET-HEAD, LAY-L0-MATCH-*, T071, T158,
T304, T324–T326, T351), отказ плана 103, отказ рантайма 150; L1 —
54 и 5 структурных отказов; L2 — 26; L3 — 9; расхождений и крахов 0;
манифест 943 исхода, MIN_CHECKED 234 → 251. Обзор корпуса —
SURVEY-2026-09-16-functions.ru.md; потребители и их полы — в журнале
docs/status/2026-09-16.ru.md.
Пол храповика MIN_CHECKED в воротах: снижение числа исполненных векторов —
регрессия среза, а не «просто меньше». Поднимается вместе с расширением плана.
Чего стоит целевой язык (замер 10.09.2026, план 0.4)
| цель | эмиттер | рантайм | раннер | харнесс |
|---|---|---|---|---|
ts |
184 | 251 | 124 | 72 |
py |
145 | 344 | 141 | 97 |
go |
181 | 471 | 238 | 162 |
rb |
149 | 255 | 113 | 73 |
rs |
189 | 448 | 163 | 106 |
java |
156 | 243 | 140 + 148 JSON | 91 |
cs |
175 | 243 | 140 | 90 |
kt |
154 | 196 | 115 + 103 JSON | 67 |
erl |
184 | 238 | 118 | 64 |
ex |
176 | 227 | 115 | 62 |
lua (14.09, план 0.5) |
229 | 541 | 154 + 133 JSON | 82 |
swift (14.09, план 0.5) |
209 | 528 | 124 + 208 JSON | 105 |
php (14.09, план 0.5) |
207 | 660 | 174 + 144 JSON | 84 |
dart (14.09, план 0.5) |
183 | 293 | 142 + 166 JSON | 99 |
bsl (14.09, план 0.6) |
310 | 858 | 184 + 243 JSON | 113 |
Эмиттер почти одинаков между языками. Дорожает рантайм там, где нет
точных целых или они многословны (math/big в Go, num-bigint в Rust),
и раннер там, где нет JSON в стандартной библиотеке (Java и Kotlin несут
свой разбор, числа в нём сохраняются текстом). Число строк «втрое» не
предсказывается: предсказывают бигинт и JSON.
Что ловит сертификация при переносе, одинаково в разных языках: собственные
max, abs и min рантайма затеняют встроенные (Python, Erlang, Elixir);
общий каталог сборки складывает все модели в один бинарь (Rust);
печать UTF-8 как latin1 (~s в Erlang); порождённое имя сталкивается с
именем рантайма (add в Go). Ни одно из этого не видно векторам, пока
ответ случайно совпадает.
Что целевой язык навязывает сам
- Go отвергает неиспользуемую переменную цикла, и эмиттер обязан её гасить;
у Go одно пространство имён — вставка строки в модели зовётся
addRow. - Целые произвольной длины есть не везде:
bigint,int,math/big,BigInteger,num-bigint— разные решения одной задачи. - Порядок обхода обязан быть детерминированным: строки лежат в массивах, а не в множествах и словарях с недетерминированным порядком; у Erlang и Elixir состояние таблиц чистое и передаётся через правила.
- Rust собирает все проекты в общий
--target-dir, поэтому крейт и бинарь именуются по каталогу вектора; C# запускается какdotnet app.dll, apphost безDOTNET_ROOTне стартует; Kotlin, Erlang и Elixir на этой машине поставлены Homebrew и в workflow профиля не входят. - Lua и Swift не дают ни длинных целых, ни пригодного JSON: у обоих свой
модуль по основанию 10^7 со знаком (деление в столбик, цифра частного
двоичным поиском) и свой разбор, где число — исходная запись. В Swift
разбор нужен потому, что
JSONSerializationотдаёт числа как NSNumber. - Lua: массивы с единицы — эмиттер сдвигает номера столбцов и ключей;
экранов
\uXXXXв строке нет — литерал печатается экранами\ddd; у функции не больше 200 локальных имён — правила лежат в массиве функций. Отказ — таблица с метатаблицейRefusedвerror, крах — любое другое значение ошибки. Проверено на Lua 5.5.0; дескриптор принимает 5.3+. - Swift: код верхнего уровня допустим только в
main.swift— раскладка кладёт раннер или харнесс под этим именем; отказ —throw, поэтому каждое выражение модели с вызовом рантайма стоит подtry; внутриenum RTголыеmax/minозначают функции рантайма — целые сравниваются черезSwift.max.swiftcна проект — десятки секунд, поэтому у цели естьbuild_many: сборки всех проектов ворот идут параллельно (одного бинаря на все модели не выходит — у каждой тот жеenum Model). Foundation не подключается. Шаг воротpy,swift— 644 с при load average около 100. - PHP:
==сравнивает строки, похожие на числа, как числа ("1.0" == "1"), поэтому текст сравнивается только===, а границы окна §31 —strcmp; инициализатор статического свойства допускает только константу — константы §54 и собственные факты пакета печатаются функциями; bcmath и gmp — не ядро (в образеphp:8.3-cliих нет), длинные целые свои, как у Lua;json_decodeотдаёт дробную запись как float — числа разбираются записью, строки JSON разбирает ядро. Литералы модели — в одинарных кавычках: без интерполяции$. - Dart: у
BigInt%евклидов, а~/усекает — остаток с усечением толькоremainder; кода верхнего уровня нет — факты пакета вpackageFacts();exit()не дожидается записи stdout, поэтому код выхода ставится черезexitCode;jsonDecodeпревращает длинное целое в double — разбор свой; в строковом литерале$— интерполяция и экранируется.dart run file.dartработает без pubspec, сборки нет. - PHP, Dart и Scala на этой машине не поставлены; проверены в docker через
обёртки PATH (
php,dart,scala-cli→docker execв долгоживущий контейнер) и, как Kotlin и Erlang, в workflow профиля не входят. Шаги ворот:py,php— 21,5 с,py,dart— 56 с. - BSL (встроенный язык 1С) исполняется OneScript (
oscript), без лицензии платформы; решение и пределы — DECISION-0235 (черновик).Числоу OneScript —.NET decimal(28–29 значащих цифр), у платформы — 38 цифр, и оба режут дробь МОЛЧА (проба OneScript 2.2.0:1/3и дробь из 30 знаков — без ошибки), громко падает только переполнение целой части. Поэтому длинные целые свои: разряды по основанию 10^7 вМассив, масштаб рядом; частное целых — только через%, а%усекает к нулю (-7 % 3 = -1), евклидов остаток свой. Цифры печатаютсяФормат(БАЗА + р, "ЧГ=0"):Строка()у платформы группирует разряды,Формат(0)безЧН— пустая строка. Регистр не различается,И— ключевое слово, аpow,round,min,max,dateметодом класса быть не могут, — операции контракта зовутсяop_*, правилаПравило_<name>со сверкой уникальности без учёта регистра. JSON свой: число остаётся записью,ЗаписьJSONпереносит строки. Модули — классыПодключитьСценарий; отказ — исключение с префиксомlaw-refused|, необработанное исключение OneScript печатает в stdout с кодом 1 (крах); stdout — UTF-8 без BOM при исходниках с BOM. Интерпретатор перебирает декартово произведение атомов на порядки медленнее: уkz.corpus.bin(правило из пяти атомов) дело шло 43 с, поэтому эмиттер выносит литералы из циклов и ставит ПРЕФИКС проверок, которые отказать не могут (фильтры и соединения не над Money), в цикл, где связаны их строки, — 0,21 с. На этой машинеoscript— релиз 2.2.0osx-arm64без подписи кода (ядро убивает его с кодом 137 до ad-hoccodesign -s -); в workflow профиля цель не входит, как Kotlin, Erlang и Elixir. Шаг воротpy,bsl— 11 с.
Границы среза
Вне плана (на 28.09.2026): условные приоритеты §117/§118, прочтения §152–§157, ограничения
§93.1, динамическая ссылка reference §30.2, Magnitude и алгебра единиц
(magnitude, unit_convert, unit_exponent), слой событий §79–§82 сверх
идентичности события (запись события и её поля, свёртка §161.1), судейский
конъюнкт с вычисляемым аргументом и гард с вызовом/if в обходе суждения
(UNDETERMINED — безопасная сторона), голый const_ref
параметра A3 в голове или атоме (позиция идентичности), параметр A3 по оси
Instant, функции с record/list/рекурсией и образцы match с полями,
кванторы в телах, average,
жизненный цикл редакции с прерывистой применимостью, вопросы why_not и
interpretation_analysis, порядок над перечислением и сравнение членов
разных перечислений (E-0067), порядок над Boolean, монотонный агрегатный
гард над выводимым предикатом (G2) — а с ним и удержание issue такого гарда
до неподвижной точки (errata E-0198): удержание наблюдаемо только на растущей
коллекции, а растущая коллекция в срез не входит (разбор — в G3 выше). Что вошло в срез
позднее первых версий, описано разделами выше: замыкание §70 и агрегаты
(0239), нормы L2 и positions (0242), календарь §84–§86 (0245), Rational
(0252), Quantity (0256), round/div_round (0259), Boolean, Natural,
границы месяца и _ §98 (0266–0268), датированные приоритеты (0269),
условный терм и вычисляемый аргумент тела (0270), функции §46, параметры
A3, let и match (0273), канал суждения §47.3 (0274), импорт чужих
пакетов (0236), инертные конструкции манифеста (0406, W1), алиасы типов §40,
std-сущности §261 и идентичности LegalContext, LegalRole, Jurisdiction,
Instant §2.15 и событие как идентичность §79 (W2),
поподстановочная ошибка головы и агрегат в голове без политики empty
(E-0265, W5). Каждая
из форм вне плана — названный отказ плана, а не тихий пропуск. Внутри среза: Date
как хранимое и сравнимое по дню значение (LAY-L0-DATE-ORDER-*),
константы §54 в деле и запросе (ERR-E0032), члены перечислений в фактах
и гардах равенства (ERR-E0067-ENUM-GUARD-*), константы в атомах тела
(ERR-E0052-DECIMAL-CANON), ключи отношений §45.1 с KEY_CONFLICT
(LAY-L0-KEYS).
Пропускаются молча только узлы провенанса §194, которые по SPEC не меняют ни
одной нормы: source_publication, publication (§27.3, вне семантического
хэша по §28), fragment. source_work §28 с 27.09.2026 — инертная
конструкция манифеста со свидетелями (DECISION-0406), а не молчаливый пропуск.
Про ключи отдельно (решение 09.09.2026, история): ключевая проекция даёт
KEY_CONFLICT при разных accepted-кортежах, evaluator при этом ничего не
выбирает и не удаляет, так что ответ бэкенда совпадал бы с голденом
(LAY-L0-KEYS). Но диагностику срез тогда не порождал, а поле, которое план
молча не читает, — именно тот пропуск, который DECISION-0188 запрещает.
Поэтому ключи до плана 0.5 были отказом: четыре вектора ушли из совпадения и
отказа по типам в отказ по ключам. С плана 0.5 (14.09.2026) модуль считает
KEY_CONFLICT сам, и ворота сверяют его с голденом.
Доказательство и байтовый контракт сюда НЕ входят: для профиля
core-auditable пришлось бы перенести на каждый целевой язык канонический
порядок §208, семантический хэш §209 и рендер proof graph. Это отдельная
работа и отдельное решение.
Metadata
Release files for arxo-codegen 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| arxo_codegen-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / arxo_codegen-0.4.0-py3-none-any.whl
| Download URL | arxo_codegen-0.4.0-py3-none-any.whl |
|---|---|
| Size | 797.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f6e43f608d13669d8eeaf9fef75bb32ceac32f45396849ba902d3881b28ed083
|
|
BLAKE2b-256 checksum How to use checksums |
d51dbbe5efdeb699c4d64bd3bade17350baaddeb0634ea3f3a549eb81dab846b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Security for arxo-codegen 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.