Skip to content

lawref.scenario

Shared scenario execution and edition projection (§31, §92, §168).

Independent Python implementation, also consumed by private impact tools. Historical error names are retained for compatibility with internal callers.

Classes

NameDescription
ImpactErrorОтказ входа отчёта: дата проекции не есть LegalTime (§2.15/§82).
ImpactWorldErrorОтказ мира отчёта О-2 (DECISION-0193): программа предъявлена не целиком,

Functions

NameDescription
edition_projectionСостояние корпуса as-of legal_time: (проекция, мета).
link_presented_worldПрограмма отчёта О-2 (DECISION-0193): (программа, id узлов корня, состав
projection_rule_lossЧто проекция §31/D1 сняла с даты: {lost, total, anchored, editions,
run_scenarioИсполнить сценарий над документом: ('result', doc) | ('error', {...}).

ImpactErrorclass#

class ImpactError(ValueError)

Bases: ValueError

Отказ входа отчёта: дата проекции не есть LegalTime (§2.15/§82).

ImpactWorldErrorclass#

class ImpactWorldError(ImpactError)

Bases: ImpactError

Отказ мира отчёта О-2 (DECISION-0193): программа предъявлена не целиком, с лишним пакетом или на байтах, разошедшихся с закреплёнными. Код хоста (FFI) — IMPACT_WORLD; текст отказа у CLI и FFI один.

codeattributeclass attributeinstance attribute#

code = 'IMPACT_WORLD'

edition_projectionfunction#

def edition_projection(document: dict, legal_time: str, scope: frozenset[str] | None = None) -> tuple[dict, dict]

Состояние корпуса as-of legal_time: (проекция, мета).

scope (DECISION-0193) — id узлов, о которых говорит МЕТА; проекция при этом снимает узлы всего документа. Связанный мир проецируется целиком — editionsAsPresented снимает условие 3 §92 со всех узлов программы, и неспроецированная зависимость осталась бы живой на любую дату, — а датировка, снятые узлы, состояния редакций и повисшие ссылки отчёта называются по корню; о зависимостях — отдельной метой того же вида. Без scope мета — обо всём документе, как прежде.

Нормативный узел снимается, если ВСЕ его разрешившиеся якоря ведут в редакции, неприменимые на момент (машина D1 — applicability.edition_state по lifecycle §31); достаточно одной применимой, чтобы узел остался. Узел без якорей — вне датировки, остаётся. Якорь, не разрешившийся ни во фрагмент, ни в редакцию, узел не датирует и называется в мете поимённо (unresolvedAnchors) — принцип §249: не угадываем, а сообщаем.

Заякоренный нормативный узел, у которого не разрешился НИ ОДИН якорь, остаётся применимым на любую дату — то есть выпадает из ответа целиком. Мета считает такие узлы отдельно (undatedNodes поимённо, anchoredNodeCount — знаменатель): именно по ним verdict отличает «право не менялось» от «датировать было нечем».

Повисшие ссылки проекция не ЧИНИТ, но ДИАГНОСТИРУЕТ (остаток v1 закрыт 27.08.2026): выживший priority_rule §116, чьи higher/lower ведут в снятый узел, называется в мете поимённо (danglingReferences) — вход движку отдаётся как есть, что с висом делать — решает читатель отчёта (§249: не угадываем, а сообщаем). Автопочинка была бы семантикой в инструменте: что означает приоритет без одной из сторон — вопрос §116, а не оркестрации.

def link_presented_world(document: dict, world: list[dict] | None, executing: bool) -> tuple[dict, frozenset[str] | None, list[dict]]

Программа отчёта О-2 (DECISION-0193): (программа, id узлов корня, состав мира). Без предъявленного мира и без исполнения — сам документ, None и пустой состав: байты отчёта прежние.

Программа исполнения — корень и его закреплённое замыкание (§23, §24; DECISION-0170: мир W = замыкание импортов C). До 11.09.2026 отчёт исполнял один CLIR как программу целиком: у us-liver-status расчёт MELD §9.1.D без unit_decl зависимости units.si (§49.2) падал в UNIT_UNKNOWN, и отчёт печатал SEMANTIC-CHANGE с «изменившимся» контрольным делом — утверждал изменение, которого в праве нет. Поэтому неполный мир при исполнении сценариев — отказ, а не исход. Без сценариев исполнять нечего (MCP law_editions спрашивает одну ось редакций корня), и один документ остаётся допустимым входом.

Порядок отказов — от формы входа к байтам: документ без имени → дубль → непредъявленный пакет замыкания → лишний пакет → связывание §23 (пины E-0123, коллизии StableId §14) → версия семантики §168.4. Замыкание строится обходом imports CLIR — ровно C §24; подтверждающих импортов прелюдии law.std.* в imports CLIR нет (замер корпуса 11.09.2026).

projection_rule_lossfunction#

def projection_rule_loss(document: dict, meta: dict) -> dict | None

Что проекция §31/D1 сняла с даты: {lost, total, anchored, editions, examples} — или None, если не сняла ничего.

ЗАЧЕМ ЭТО ВООБЩЕ ЕСТЬ. Инструменты слоя О спрашивают право НА ДАТУ, то есть считают по проекции, а не по всему пакету. Правило, снятое с даты, в ответе неотличимо от правила, которому не хватило факта: разбор блокеров §185 честно печатает «не закрыто: sogovor_qalyn_mal», а поиск лазеек честно печатает «путей не найдено» — и читатель делает ровно неверный вывод, что дело чего-то не доказало, а лазеек нет. Инструмент при этом ЗНАЕТ причину: edition_projection возвращает вторым значением состояния редакций и список снятых узлов.

Замерено на kz-tuystyq (process-run): из 93 правил на ЛЮБУЮ дату остаётся 5 — те, что компилятор породил из самой procedure и потому не заякорил; все 88 заякоренных сняты, потому что редакция TUYSTYQ_RU не объявляет ни adopted, ни in_force (обычай не вводили в действие датой, и пакет объясняет это в 06-sources.law). На vory.corpus.ponyatiya (loophole) снимаются ВСЕ 28 правил — там ни одна из семи редакций не несёт lifecycle вовсе.

Считаются ПРАВИЛА, а не узлы вообще: снятый фрагмент или symbol_decl на вывод не влияет, и мешать их в одно число значило бы пугать шумом.

anchored — знаменатель для вопроса «осталось ли ХОТЬ ЧТО-ТО, что вообще можно датировать». Правило без якорей вне датировки по построению (§31: узел без якорей остаётся применимым на любую дату), и его выживание не говорит о праве акта ничего: у intl-istanbul-draft-2022 снято 136 правил из 149 — то есть ВСЕ 136 заякоренных, а уцелевшие 13 порождены компилятором из procedure и якорей не несут. Считать такую проекцию «частичной потерей» значило бы пропустить ровно тот случай, ради которого счёт и заведён.

run_scenariofunction#

def run_scenario(document: dict, scenario: dict, extra_options: dict | None = None, editions_as_presented: str | None = None) -> tuple[str, dict]

Исполнить сценарий над документом: (‘result’, doc) | (‘error’, {…}).

Контракт отказов — тот же, что у run_vector: pre-evaluation исключение (календарь, лимиты) становится значением, а не падением инструмента, — Иначе сценарий, роняющий ОДНУ из редакций, обрушил бы весь отчёт вместо того, чтобы показать расхождение исходов.

extra_options — ВНЕШНИЕ РЕСУРСЫ вызывающего (сегодня: байты календарного набора §85), а не вход семантики. Они кладутся мимо case, потому что caseHash §170 канонизирует дело целиком, а байты в JSON не канонизируются вовсе: положить их в case.options значит уронить КАЖДЫЙ вызов CanonError. Пары «id набора» довольно, и она в деле уже есть — options.calendarSnapshot.

editions_as_presented (§92, errata E-0167) — дата, на которую состав редакций document уже спроецирован ВЫЗЫВАЮЩИМ: при ней evaluate не исполняет условие 3 §92 по дате права дела. Без неё сценарий над ПРОЕКЦИЕЙ исполнялся бы по пересечению двух проекций — на дату проекции и на дату дела; см. build_edition_report.

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.