# lawref.evaluator.rules

*module*

Статический анализ правил, общий для strict и defeasible замыканий.

Барьер полноты [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)/[§190](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#190-rule-safety): агрегат читает предикат целиком, поэтому источник
обязан быть завершён до чтения. Оба замыкания задают этот вопрос одинаково —
и получают одинаковый ответ.

## lawref.evaluator.rules.aggregate_barrier_problem

*function*

```python
def aggregate_barrier_problem(node: dict, defeasible: set[str] | frozenset[str]) -> str | None
```

[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)/[§190](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#190-rule-safety): агрегат (домен квантора) читает предикат ЦЕЛИКОМ, поэтому
его источник обязан быть завершён до чтения. До DECISION-0088 завершённым
признавался только невыводимый предикат; теперь строгие производители
завершаются стратами строгого слоя (`strict.strict_ranks`), и барьер
держит лишь СТРОГОГО читателя над предикатом с ПОРАЖАЕМЫМИ
производителями: страты поражаемого слоя есть только у поражаемых правил.
Errata E-0112: обёртка `monotone(P)`/`supported(P)` барьер НЕ снимает —
перечисление есть ребро `completion` [§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) независимо от статуса.
Errata E-0116 барьер тоже не трогает: изъятие снимает НЕМОНОТОННОСТЬ
перечисления, но не поражаемость производителей — опора поражаемого
правила может быть отнята дефитером, и тест `monotone(P)` над ней не
монотонен. Поэтому здесь зовётся `all_generator_reads`, а не
`generator_reads`.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L1026-L1049)

## lawref.evaluator.rules.all_generator_reads

*function*

```python
def all_generator_reads(node: dict) -> list[tuple[str, str]]
```

ВСЕ generator-чтения правила, включая изъятые E-0116, — для барьера
[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)/[§190](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#190-rule-safety): изъятие снимает немонотонность перечисления, но не
поражаемость производителей.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L727-L734)

## lawref.evaluator.rules.body_condition_literals

*function*

```python
def body_condition_literals(node: dict) -> list[tuple[str, dict]]
```

Чтения условных термов тела и scope литералами — носитель
`body_condition_reads`; полярность нужна ожиданию замыкания [§70](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#70-closed-world-declarations).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L545-L551)

## lawref.evaluator.rules.body_condition_reads

*function*

```python
def body_condition_reads(node: dict) -> list[tuple[str, str]]
```

Чтения опоры внутри условных термов [§56](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#56-conditional-expression) ТЕЛА и scope: [(вид статуса,
предикат)] — errata E-0177.

Позиция терма в теле не важна: гард-сравнение, формула [§64.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#642-отношение-округления-над-сертифицированными-границами-errata-e-0136), квантор
[§52](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#52-finite-domains), фильтр comprehension, аргумент литерала. Гард, истинный на ветви
`else`, публикует голову, пока тест ложен, и вывод её не отзывает, —
немонотонность та же, что у условной головы (`head_condition_reads`).

До errata `flatten_body` отдавал гард целиком (`guard`), и ранги, отказы и
граф [§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) его чтения пропускали: читатель вставал в страту производителя.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L530-L542)

## lawref.evaluator.rules.closure_levels

*function*

```python
def closure_levels(nodes: list[dict]) -> dict[str, int] | None
```

Уровни замыканий [§70](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#70-closed-world-declarations) (errata E-0113): уровень замыкания на единицу выше
уровней всех замыканий, чьи негативы читают — транзитивно, через любую
зависимость — производители его предиката или домена; без такой
зависимости — уровень 1. Считается по ТОМУ ЖЕ графу, что и
`stratification_problem`: вершина-замыкание достигает другую вершину-
замыкание ровно тогда, когда её производители читают тот негатив.
`None` — цикл между замыканиями (его называет `stratification_problem`
раньше, чем сюда доходит вызов; здесь — страховка).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L1238-L1274)

## lawref.evaluator.rules.closure_waits

*function*

```python
def closure_waits(rules: list[tuple[dict, list[tuple[str, dict]]]], nodes: list[dict], derived: set[str] | frozenset[str]) -> dict[str, frozenset[str]]
```

Ожидание замыканий [§70](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#70-closed-world-declarations) строгим слоем (errata E-0174): id строгого
правила → замыкания, до материализации которых оно не исполняется.

[§70](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#70-closed-world-declarations) ставит замыкание вершиной графа страт: `producers(P ∪ domain) →
closure(P) → readers(¬P)`. Сэндвич [§231.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/31-part-xxx-scalability.ru.md#2311-lazy-closure-и-comprehensions) повторяет строгий фикспойнт
до замыкания и после него, а вывод append-only. Правило, чей тест
опровергается негативом замыкания (`unknown(P)`, `not_known(¬P)`,
перечисление `¬P`), сработало бы в проходе ДО замыкания и не отозвалось бы.
Такое правило ждёт замыкание — это подъём над вершиной, а не отказ.
Ожидание транзитивно: правило ждёт и то, чего ждут строгие производители
опор, опровергающих его тест, а производитель завершён, когда завершены
все его чтения. Правило, чей тест замыкание делает только истинным
(голый `not P`), не ждёт: второй проход сэндвича его и так исполняет.

Значения — только id замыканий, достижимых по графу [§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification), поэтому
правило не ждёт замыкания, которое само питает: уровни E-0113 ставят такое
замыкание выше. Пустой словарь — прежний сэндвич байт в байт.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L1315-L1387)

## lawref.evaluator.rules.condition_leaves

*function*

```python
def condition_leaves(condition) -> list[dict] | None
```

Листья условия цели [§124](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#124-goal-types) (errata E-0218): связки `and`/`or` над
литералами и established-литералами. `None` — форма вне подмножества.

Лист читается парой САМОГО литерала: `established`, поставленный
понижением по умолчанию [§66](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#66-rule-body-default), Boolean-подъёмом [§64.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#641-lifting-data-boolean-в-formula) здесь не является —
иначе `condition not A` при неизвестном `A` давал бы контрпример [§137](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/19-part-xviii-norm-lifecycle-fulfillment-violation.ru.md#137-maintenance-satisfaction).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L329-L351)

## lawref.evaluator.rules.condition_literal

*function*

```python
def condition_literal(condition) -> dict | None
```

payload.goal.condition → ground-литерал (v1: атом или established-атом).

Живёт здесь, а не в `norms.py`, по той же причине, что и классификации
правил: тот же вопрос задают снаружи — `norm_goal_status` ниже и ворота
`verify/ci/gates/silence/check_dead_rules.py`. Вторая копия списка
допустимых форм разошлась бы с первой молча.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L312-L326)

## lawref.evaluator.rules.condition_reads

*function*

```python
def condition_reads(node: dict) -> list[tuple[str, str]]
```

Чтения условных термов [§56](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#56-conditional-expression) головы и тела вместе — для рангов и графа
[§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification), где позиция терма вид ребра не меняет (errata E-0176, E-0177).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L554-L557)

## lawref.evaluator.rules.defeasible_chain_predicates

*function*

```python
def defeasible_chain_predicates(nodes: list[dict]) -> set[str]
```

Errata E-0172 ([§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) п. 5/[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)): предикаты, которые строгая цепочка
выводит из поражаемого вывода, — без самих голов поражаемых правил (у тех
свой отказ DECISION-0088 и своё сообщение).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L693-L700)

## lawref.evaluator.rules.defeasible_head_literals

*function*

```python
def defeasible_head_literals(nodes: list[dict]) -> set[tuple[str, str]]
```

Errata E-0238: пары (предикат, полярность) голов обычных defeasible-
кандидатов [§104](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#104-defeasible-candidate) — без дефитеров: дефитер вывода не утверждает ([§107](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#107-defeat) п. 3),
и строгая опора противоположного знака с ним комплемента не образует.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L619-L630)

## lawref.evaluator.rules.defeasible_predicates

*function*

```python
def defeasible_predicates(nodes: list[dict]) -> set[str]
```

Предикаты с ПОРАЖАЕМЫМ производителем (defeasible/defeater, [§104](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#104-defeasible-candidate)) —
DECISION-0088: строгий читатель `not_known`/агрегата над ними отказывается.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L606-L616)

## lawref.evaluator.rules.defeasible_rule_status

*function*

```python
def defeasible_rule_status(node: dict, derived: set[str]) -> tuple[str, str | None, list[tuple[str, dict]]]
```

Та же классификация для [§104](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#104-defeasible-candidate) (defeasible/defeater) — порт тела
`defeasible._rule_filter_l1`. Полярность head здесь ЛЮБАЯ: барьеры [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)
ограничивают строгое замыкание, а не поражаемое.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L221-L242)

## lawref.evaluator.rules.derived_predicates

*function*

```python
def derived_predicates(nodes: list[dict]) -> set[str]
```

Предикаты, которые программа выводит правилами (любой силы).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L594-L603)

## lawref.evaluator.rules.effect_reachable_predicates

*function*

```python
def effect_reachable_predicates(nodes: list[dict]) -> set[str]
```

Предикаты, достижимые от голов эффектов полномочий [§127](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#127-power) строго-
позитивными рёбрами (errata E-0134): `after` (у `modify` — и `before`)
каждого `norm_template` модальности power, затем головы строгих правил,
чьё тело читает такой предикат через `established`/`supported`/`monotone`,
до фикспойнта. Поражаемые правила цепочку не продолжают: после
материализации они не повторяются (DECISION-0021 [§4.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#4-не-цели-01)) и опоры не дают.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L633-L651)

## lawref.evaluator.rules.generator_problem

*function*

```python
def generator_problem(node: dict) -> str | None
```

Причина, по которой generator comprehension правила вне исполнимого
подмножества, либо None ([§52.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#521-finite-relation-comprehensions), errata E-0219).

Comprehension стоит в теле, голове или `scope` — под агрегатом [§59](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#59-aggregates) или
доменом квантора [§52](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#52-finite-domains), на любой глубине. До errata такой generator не
проверялся при классификации вовсе: его отвергал перебор уже во время
вычисления, и ValueError уносил evaluation-документ целиком — на ЛЮБОЙ
вопрос к программе, а ворота молчания падали исключением вместо того,
чтобы назвать правило.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L245-L263)

## lawref.evaluator.rules.generator_reads

*function*

```python
def generator_reads(node: dict, derived: set[str] | frozenset[str] = frozenset()) -> list[tuple[str, str]]
```

Чтения generator-ов агрегатов [§59](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#59-aggregates) и доменов кванторов [§52](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#52-finite-domains) правила —
(статус, предикат) в порядке встречи, без повторов, тело И голова.
DECISION-0088: это зависимости [§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) для рангов обоих слоёв; errata
E-0112: каждое — ребро `completion`, и статус обёртки (`monotone`,
`supported`) вид ребра НЕ меняет: перечисление множества не монотонно.

Errata E-0116: изъяты чтения МОНОТОННОГО АГРЕГАТНОГО ГАРДА [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata) — их
отдаёт `monotone_guard_reads`, и это рёбра `monotone`, а не `completion`.
`derived` — предикаты, выводимые правилами программы
(`derived_predicates`): без них гард не распознать, поэтому пустое
умолчание означает «выводимых нет» и изъятие шире не делает.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L703-L716)

## lawref.evaluator.rules.goal_condition_compound

*function*

```python
def goal_condition_compound(goal: dict) -> dict | None
```

Составное условие цели [§124](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#124-goal-types) (E-0218), исполнимое по [§64](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#64-conjunction-и-disjunction), — или None.
Атом сюда не входит: его разбирает `goal_condition_literal` прежним путём.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L366-L374)

## lawref.evaluator.rules.goal_condition_literal

*function*

```python
def goal_condition_literal(goal: dict) -> dict | None
```

[§124.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#1243-forbearance-sugar): forbearance reads the negative action atom (E-0179).

Keep the authored goal intact: conflicts and weak permission use its
action. Only the lifecycle/knowledge projection is desugared.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L393-L405)

## lawref.evaluator.rules.goal_condition_sides

*function*

```python
def goal_condition_sides(condition: dict, store) -> tuple[list[str], list[str]]
```

[§64](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#64-conjunction-и-disjunction) над парами листьев условия цели (errata E-0218): стороны `t`/`f`
и их опоры. `P and Q = (P.t and Q.t, P.f or Q.f)`, `P or Q = (P.t or Q.t,
P.f and Q.f)`; опоры стороны — объединение опор листьев, давших её.
Лист — пара самого литерала (`support_sides`), без подъёма [§64.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#641-lifting-data-boolean-в-formula).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L377-L390)

## lawref.evaluator.rules.head_condition_literals

*function*

```python
def head_condition_literals(node: dict) -> list[tuple[str, dict]]
```

Чтения условного терма головы [§56](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#56-conditional-expression) литералами: (вид статуса, литерал) —
носитель `head_condition_reads`; полярность нужна ожиданию замыкания [§70](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#70-closed-world-declarations)
(errata E-0174).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L507-L527)

## lawref.evaluator.rules.head_condition_reads

*function*

```python
def head_condition_reads(node: dict) -> list[tuple[str, str]]
```

Чтения опоры внутри условного терма ГОЛОВЫ [§56](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#56-conditional-expression): [(вид статуса, предикат)].

Такое чтение немонотонно ровно так же, как `not_known` в теле: ветвь `else`
срабатывает, ПОКА тест ложен, и если предикат получит опору позже, правило
сработает второй раз — а факт, выведенный ранним `else`, останется в store.
Поэтому читатель обязан стоять ВЫШЕ страты производителей ([§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification)/[§113](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#113-default-negation)), и
зависимость обязана быть видна ранжированию.

До errata: чтения жили только в теле, `deps_of` их и собирал; условие в
голове не попадало ни в `conjuncts`, ни в `generator_reads`, и правило
вставало в нулевую страту рядом с производителем.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L491-L504)

## lawref.evaluator.rules.monotone_guard_aggregates

*function*

```python
def monotone_guard_aggregates(node: dict, derived: set[str] | frozenset[str]) -> list[dict]
```

Агрегаты [§59](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#59-aggregates) МОНОТОННЫХ АГРЕГАТНЫХ ГАРДОВ [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)
(errata E-0116).

Гард — ПОЗИТИВНЫЙ конъюнкт тела (голова и любая иная позиция не считаются)
вида `AGG(collect v … where G) OP c`, где: пара `AGG`/`OP` — из
`_MONOTONE_GUARD_OPS`; `c` не перечисляет ничего сам (в терме порога нет
comprehension, значит нет и чтения выводимого предиката); `G` читает
выводимые предикаты ТОЛЬКО через `monotone`/`supported` [§65](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#65-status-tests).

Знак слагаемых `sum` статика не видит, и требовать конъюнкт `v >= 0`
нельзя: он МЕНЯЕТ каноническое тело [§206](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#206-rule-splitting) и вместе с ним порядок
конъюнктов — измерено на `us.ofac_50`, где добавленный конъюнкт передвинул
гард перед `monotone(blocked(lead))` и сумма считалась по пустой
коллекции (`EMPTY_AGGREGATE` [§59](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#59-aggregates)) в первом же раунде. Поэтому проверка
отрицательного слагаемого — на ИСПОЛНЕНИИ гарда:
`MONOTONE_GUARD_NEGATIVE_ADDEND` ([§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata), errata E-0116).

Такой тест не убывает вместе с множеством: least fixed point [§103](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#103-strict-closure) по нему
определён так же, как по точечному `monotone(P)`, и generator-чтения —
рёбра `monotone`, а не `completion`.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L838-L872)

## lawref.evaluator.rules.monotone_guard_growing

*function*

```python
def monotone_guard_growing(node: dict, derived: set[str] | frozenset[str]) -> bool
```

Растёт ли коллекция монотонного агрегатного гарда [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata) ВНУТРИ страты
(errata E-0198).

Растёт ровно тогда, когда generator гарда читает ВЫВОДИМЫЙ предикат (по
[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata) — только через `monotone(P)`/`supported(P)` [§65](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#65-status-tests)): правило стоит в
страте своих производителей и повторяется, пока гард не выполнен, поэтому
коллекция первого прохода — подмножество коллекции неподвижной точки, и
ошибка вычисления над ней ещё не окончательна. У гарда, чей generator
читает одну эмпирику, коллекция заморожена входом дела: первый проход
равен неподвижной точке, удерживать нечего, и байты такого правила правка
E-0198 не двигает по построению.

Замер 20.09.2026 по 1 281 снимку корпуса: монотонных агрегатных гардов
353, растущих — 32 в 27 правилах, и среди растущих не-`count` ровно один
(`us-ofac-50#BlockedEntityByAggregateOwnership2014`).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L927-L944)

## lawref.evaluator.rules.monotone_guard_reads

*function*

```python
def monotone_guard_reads(node: dict, derived: set[str] | frozenset[str]) -> list[tuple[str, str]]
```

Чтения generator-ов МОНОТОННЫХ агрегатных гардов [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata) (errata E-0116) —
(статус, предикат) в порядке встречи, без повторов. Дополнение к
`generator_reads`: вместе они дают все generator-чтения правила.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L719-L724)

## lawref.evaluator.rules.monotone_guard_sum_aggregates

*function*

```python
def monotone_guard_sum_aggregates(node: dict, derived: set[str] | frozenset[str]) -> list[dict]
```

Монотонные гарды с агрегатом `sum` ([§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata), errata E-0116) — те, чьи
слагаемые исполнитель обязан проверить на знак: монотонность суммы
держится на неотрицательности, а статика её не видит.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L919-L924)

## lawref.evaluator.rules.norm_goal_status

*function*

```python
def norm_goal_status(template: dict) -> tuple[str, str | None]
```

Классификация цели [§124](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#124-goal-types): (исход, причина).

Дефект, ради которого заведена (измерен 30.08.2026 на ст. 910 п. 2 ГК РК,
Особенная часть). Цель `condition a(x) or b(x)` проходит `lawc check` и
лоуверинг молча — схема `AchievementGoal` объявляет condition как
`Formula`, то есть [§124](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#124-goal-types) дизъюнкцию РАЗРЕШАЕТ, — а на исполнении
обязанность не разряжается никогда. Улика на одном деле: соседняя
обязанность с однолитеральной целью перешла в SATISFIED, а эта,
содержащая тот же литерал внутри `or`, осталась ACTIVE, и ни одного issue
выдано не было. Класс тот же, что у `or` в теле правила, но тише: там
исполнитель хотя бы печатает `NON_EXECUTABLE_RULE`.

Отказ v1 честен (неверных ответов не даёт), но обязан быть НАЗВАН —
отсюда причина, которую печатает `norms.py` и требуют ворота молчания.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L414-L459)

## lawref.evaluator.rules.norm_rule_status

*function*

```python
def norm_rule_status(node: dict, template_ids: set[str]) -> tuple[str, str | None, list[tuple[str, dict]]]
```

Классификация правила с norm-головой [§135](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/19-part-xviii-norm-lifecycle-fulfillment-violation.ru.md#135-activation) — порт цикла `norms.py`.
Два отказа: шаблон не разрешается и тело вне v1-подмножества. Именно
здесь пропали `KurultaiDissolutionBarrier` и `PresidentialOfficialImmunityRule`
Конституции — у них норм-голова, поэтому строгое замыкание их не видит
вовсе, а тело с `or` не проходит `flatten_body`.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L279-L309)

## lawref.evaluator.rules.rule_execution_status

*function*

```python
def rule_execution_status(node: dict, derived: set[str], template_ids: set[str], defeasible: set[str] | frozenset[str] = frozenset(), effect_reachable: set[str] | frozenset[str] = frozenset(), defeasible_chain: set[str] | frozenset[str] = frozenset(), defeasible_heads: set[tuple[str, str]] | frozenset[tuple[str, str]] = frozenset()) -> tuple[str, str | None]
```

Единая точка для внешнего наблюдателя: пропустит ли исполнитель это
правило и почему. Диспетчер по силе и виду головы — ровно тот, что
разложен по трём модулям оракула (`strict`, `defeasible`, `norms`).

Оговорка: покрывает СТАТИЧЕСКИЕ отказы. Отказы, видимые только на деле
(power без exercise-паттерна [§127](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#127-power), priority с несвязанными переменными
[§118](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/17-part-xvi-priority-declarations.ru.md#118-priority-policy)), рождаются в `effects.py`/`defeasible.py` во время вычисления и
статикой не предсказуемы — ворота их не видят и не притворяются.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L462-L488)

## lawref.evaluator.rules.scope_conjuncts

*function*

```python
def scope_conjuncts(node: dict) -> list[tuple[str, dict]]
```

Конъюнкты `scope` правила — [§90](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/13-part-xiii-context-scope-applicability.ru.md#90-scope-formula): «`scope` семантически объединяется с
`when`, но сохраняется отдельно в IR для indexing, analysis и объяснений».

Слово «объединяется» нормативно, и до 28.08.2026 обе реализации его не
исполняли: нетривиальный scope давал `skipped` с причиной «за пределами
v1». Отказ был ЧЕСТНЫМ (неверных ответов не давал), но цена его молчалива —
норма, у которой условие применимости выражено по [§91](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/13-part-xiii-context-scope-applicability.ru.md#91-applicability-status) отдельно от
условия срабатывания [§91.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/13-part-xiii-context-scope-applicability.ru.md#911-trigger-status), не исполнялась вовсе. В корпусе так молчали
четырнадцать норм Закона «О правовых актах», включая пункт 1 статьи 5
(«все иные акты не могут противоречить нормативным постановлениям
Конституционного Суда»).

Разбор — тот же `flatten_body`, а не второй: [§90](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/13-part-xiii-context-scope-applicability.ru.md#90-scope-formula) объединяет scope с when,
значит и подмножество конструкций у них одно. Своя копия разошлась бы с
телом ровно так же, как разошлись бы два списка исходов классификации.
Тривиальный scope (`None` либо `true`) даёт пустой список — форма
`{"kind": "boolean", "value": true}` уже возвращает `[]` из `flatten_body`.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L12-L34)

## lawref.evaluator.rules.stratification_problem

*function*

```python
def stratification_problem(nodes: list[dict]) -> dict | None
```

[§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) п.1–2: цикл предикатного графа с не-monotone ребром — issue, иначе None.

Детект как в статике lawc: для каждого НЕ-monotone ребра (потребитель →
продюсер) ищется обратная достижимость по полному графу; найденный путь
замыкает цикл, содержащий это ребро. Только-monotone циклы (transitive
closure через `supported` [§103](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#103-strict-closure)) легальны и не репортятся. Ребро
`completion` (E-0112) и рёбра вершин-замыканий (E-0113) — не monotone.

Объём — циклы, в которых участвует хотя бы одно strict-правило: именно их
strict-LFP [§103](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#103-strict-closure) иначе молча вычислил бы по немонотонному оператору
(`established` гасится приходом негативной опоры: TRUE_ONLY → BOTH).
Чисто defeasible-циклы детектируются расхождением рангов в
`defeasible_closure` и репортятся своим сообщением.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L1427-L1466)

## lawref.evaluator.rules.strict_positive_chain

*function*

```python
def strict_positive_chain(nodes: list[dict]) -> list[tuple[str, list[str]]]
```

Строго-позитивные рёбра программы: (голова строгого правила, предикаты
его положительных конъюнктов `established`/голый атом, `supported`,
`monotone` в scope и теле) — в порядке узлов. Общий носитель обходов
E-0134 (эффект полномочия) и E-0172 (поражаемый вывод): оба спрашивают,
куда поздний производитель доходит строгими правилами, и одна копия списка
статусов не разойдётся со второй. Правило вне v1-разбора рёбер не даёт.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L654-L676)

## lawref.evaluator.rules.strict_positive_closure

*function*

```python
def strict_positive_closure(seeds: set[str], chain: list[tuple[str, list[str]]]) -> set[str]
```

Семена плюс головы строгих правил, читающих достигнутый предикат, до
фикспойнта (`strict_positive_chain`).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L679-L690)

## lawref.evaluator.rules.strict_rule_status

*function*

```python
def strict_rule_status(node: dict, derived: set[str], defeasible: set[str] | frozenset[str] = frozenset(), effect_reachable: set[str] | frozenset[str] = frozenset(), defeasible_chain: set[str] | frozenset[str] = frozenset(), defeasible_heads: set[tuple[str, str]] | frozenset[tuple[str, str]] = frozenset()) -> tuple[str, str | None, list[tuple[str, dict]]]
```

Классификация строгого правила: (исход, причина, конъюнкты).

Живёт здесь, а не в теле цикла `strict_closure`, потому что тот же вопрос
задают снаружи: ворота `verify/ci/gates/silence/check_dead_rules.py` обязаны знать, какие
правила корпуса исполнитель молча пропустит. Вторая копия этого списка
разошлась бы с первой — и ворота докладывали бы о живых нормах, которых
нет, либо молчали о мёртвых (тот же класс отказа, что у реестров в
CLAUDE.md). Один список, два потребителя.

DECISION-0088 (WP-41): негативная голова [§99](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/15-part-xiv-rules.ru.md#99-head), `not_known` [§113](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#113-default-negation) и агрегат по
выводимому предикату [§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata) исполняются стратами строгого слоя
(`strict.strict_ranks`). Отказ остаётся у строгого читателя `not_known`
или агрегата над предикатом с ПОРАЖАЕМЫМИ производителями (`defeasible`):
[§113](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#113-default-negation) ставит читателя выше страты производителей, а страты поражаемого слоя
есть только у поражаемых правил — такое правило обязано быть defeasible.

Errata E-0134 ([§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)/[§127](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#127-power)): тот же отказ у строгого `not_known`/`unknown`/
`refuted` над предикатом из `effect_reachable` — достижимым от головы
эффекта полномочия строго-позитивной цепочкой (`effect_reachable_predicates`):
эффект материализуется после всех страт ([§280.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/40-part-xxxvii-a-operational-algorithm.ru.md#2803-norm-runtime)), и умолчание считалось бы
по снимку без него, не отзываясь потом.

Errata E-0172 ([§110](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#110-stratification) п. 5/[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)): тот же отказ у строгого `not_known` и
перечисления над предикатом из `defeasible_chain` — выводимым строгой
цепочкой из поражаемого вывода (`defeasible_chain_predicates`, без самих
поражаемых голов). Strict closure страты исполняется до её кандидатов,
поэтому такой предикат полон лишь стратой выше источника, а у строгого
читателя страт поражаемого слоя нет. Сообщение своё: у предиката нет
поражаемого производителя, есть цепочка.

Errata E-0238 ([§107](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#107-defeat)/[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)/[§127](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#127-power)): отказ и у строгого правила, чья голова —
КОМПЛЕМЕНТ головы обычного defeasible-кандидата (`defeasible_heads`: пары
«предикат, полярность» правил силы defeasible), а тело или scope
положительно читает предикат из `effect_reachable`: противник поражаемого
вывода опоздал бы к его conflict group, и документ получил бы `BOTH`.
Строгая опора той же полярности, что у кандидатов, комплемента не создаёт
и не отклоняется.

Errata E-0176 ([§56](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#56-conditional-expression)/[§111](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#111-порядок-evaluation-strata)): условный терм головы — status-sensitive читатель
при любом статусе теста (ветвь `else` публикуется, пока тест ложен), и отказ
звучит над всеми тремя поздними производителями: поражаемым, звеном
цепочки и эффектом полномочия.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/evaluator/rules.py#L42-L218)
