# lawref.process

*module*

Процессный слой — О-5 плана LAYERS-NEXT (моделирование процессов поверх
профиля `procedure` [§159](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#159-статус-procedure-profile)–[§164](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#164-invalid-transitions), DECISION-0013).

Оркестрация без семантики (инвариант CLAUDE.md №5): модуль восстанавливает
структуру автомата из УЖЕ порождённых компилятором узлов CLIR и исполняет дело
существующими входами — `evaluate` [§168](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#168-case-file)–[§178](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/25-part-xxiv-queries-and-results.ru.md#178-compliance-result) через `impact.run_scenario`,
проекция as-of [§31](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#31-lifecycle) через `impact.edition_projection`. Ни одно правило права
здесь не интерпретируется; отчёт сравнивает и называет выходы движка.

## Почему структура восстановима механически

Десугаризация [§160](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#160-procedure-declaration) (DECISION-0013 [§2.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#21-23-примитива-смешивали-уровни-системы)) эмитирует ровно три вида правил, и
каждое несёт ребро автомата в собственных термах — читать исходник не нужно:

| Правило | Форма | Что даёт |
|---|---|---|
| `<P>/initial` | `entered_state(v, S) :- established(procedure_instance(v))` | начальное состояние |
| `<P>/<T>/valid` | `valid_transition(v, T) :- attempted(v,T) ∧ supported(entered_state(v, F)) ∧ Gi` | состояние-ИСТОЧНИК и гарды |
| `<P>/<T>/enters` | `entered_state(v, O) :- supported(valid_transition(v, T))` | состояние-ЦЕЛЬ |

Восстановление идёт по ПРЕДИКАТАМ профиля, а не по строкам id: при двух и
более процедурах в пакете имена квалифицируются (`P__valid_transition`,
DECISION-0013 [§2.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#23-не-была-определена-семантика-условия-правила-при-конфликте)), и группировка по квалификатору отделяет автоматы друг от
друга там, где id-шаблон одинаков. Имя процедуры при этом читается из id —
оно больше нигде в CLIR не сохранено.

## Что объявлено границей, а не забыто

- **`terminal` в CLIR отсутствует.** Терминальность [§160](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#160-procedure-declaration) — маркер исходника,
  проверяемый компилятором (`LDC-E1313`), и в узлы не попадает. Поэтому
  состояние без исходящих переходов называется `SINK_STATE` и лежит в
  `notes`, а не в `findings`: отличить законный терминал от тупика по CLIR
  нельзя, и врать об этом инструмент не будет ([§249](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/33-part-xxxii-interoperability.ru.md#249-legalruleml-adapter) — не угадываем, сообщаем).
- **`current_state` [§161](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#161-event-sourced-semantics) не вычисляется** — его нет в срезе 0.1 (DECISION-0013
  [§2.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#22-четырёхзначной-логики-самой-по-себе-недостаточно): нет времени событий [§79](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#79-event-declaration)–[§81](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#81-event-identity)). Кадр называет `enteredStates` —
  «входило ли когда-либо», множество, а не точку. Возврат в состояние
  неотличим от невыхода из него, и это свойство ядра, а не отчёта.
- **Доступные шаги считаются только для последнего кадра.** Гипотетический
  прогон стоит по вызову `evaluate` на переход; на каждом кадре это удорожало
  бы обход в |steps| раз. Граница названа в манифесте (`availableStepsAt`).
- **Событие `on E` [§79](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#79-event-declaration) в валидность перехода не входит** — его не исполняет
  ядро (DECISION-0013 [§2.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#22-четырёхзначной-логики-самой-по-себе-недостаточно)). Журнал даёт попытку перехода эмпирическим
  фактом [§164](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#164-invalid-transitions), ровно как срез и предусматривает.

## Вердикт

Три исхода, и средний из них — не дефект инструмента, а предмет [§164](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#164-invalid-transitions):

- `CLEAN` (0) — дело прошло без нарушенных позиций и без попыток без эффекта;
- `FINDINGS` (1) — есть нарушенная позиция [§140](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/19-part-xviii-norm-lifecycle-fulfillment-violation.ru.md#140-violation), попытка перехода без
  правового эффекта [§164](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#164-invalid-transitions), отказ движка либо застревание (ни один переход не
  доступен, а достигнутые состояния не тупиковые);
- `JUDGMENT` (3) — движок ответил `REQUIRES_JUDGMENT` [§47.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#473-judgment): ход дела зависит
  от человека, и отчёт не выдаёт это ни за «чисто», ни за «нарушение».

## Утверждение о деле и утверждение о прогоне не смешиваются

Отдельная линия, стоившая правки уже написанного слоя. «Переход не признан
состоявшимся» [§164](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#164-invalid-transitions) — утверждение о ПРАВЕ; «посчитать не удалось» — утверждение
о ПРОГОНЕ. Первая редакция сливала их: при отказе движка на каждом вызове
отчёт печатал `ATTEMPT_WITHOUT_EFFECT`, то есть утверждал о деле, не вычислив
ничего, а журнал без попытки в тех же условиях давал `CLEAN` и код 0.

Отсюда `REFUSED_STATUSES` и три следствия: у попытки есть поле `computed`;
`ATTEMPT_WITHOUT_EFFECT` эмитируется только из вычисленного ответа; `STUCK` не
утверждается при непосчитанных шагах, усечении бюджета и любом отказе.
Отказ называется сам — находкой `EXECUTION_REFUSED` с кодом и запросом.

## lawref.process.ATTEMPTED

*attribute* · *module attribute*

```python
ATTEMPTED = 'attempted_transition'
```

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

## lawref.process.AXES

*attribute* · *module attribute*

```python
AXES = ('decisionTime', 'knowledgeTime')
```

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

## lawref.process.BLOCKING_STATIC

*attribute* · *module attribute*

```python
BLOCKING_STATIC = ('NO_INITIAL_STATE', 'UNREACHABLE_STATE', 'DEAD_TRANSITION', 'TRANSITION_WITHOUT_TARGET')
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L116-L117)

## lawref.process.DEFAULT_BUDGET

*attribute* · *module attribute*

```python
DEFAULT_BUDGET = 2000
```

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

## lawref.process.ENTERED

*attribute* · *module attribute*

```python
ENTERED = 'entered_state'
```

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

## lawref.process.HOLDING_STATUSES

*attribute* · *module attribute*

```python
HOLDING_STATUSES = ('TRUE_ONLY', 'BOTH')
```

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

## lawref.process.INSTANCE

*attribute* · *module attribute*

```python
INSTANCE = 'procedure_instance'
```

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

## lawref.process.JOURNAL_SCHEMA_VERSION

*attribute* · *module attribute*

```python
JOURNAL_SCHEMA_VERSION = 'law.process.journal/0.2'
```

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

## lawref.process.NODE_PREDICATE_FIELDS

*attribute* · *module attribute*

```python
NODE_PREDICATE_FIELDS = (('instance', 'instancePredicate'), ('attempted', 'attemptedPredicate'), ('valid', 'validPredicate'), ('entered', 'enteredPredicate'), ('left', 'leftPredicate'), ('initial', 'initialPredicate'), ('stateBefore', 'stateBeforePredicate'), ('currentState', 'currentStatePredicate'), ('completed', 'completedPredicate'))
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L82-L88)

## lawref.process.REFUSED_STATUSES

*attribute* · *module attribute*

```python
REFUSED_STATUSES = ('ERROR', 'BUDGET_EXHAUSTED')
```

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

## lawref.process.SCHEMA_VERSION

*attribute* · *module attribute*

```python
SCHEMA_VERSION = 'law.process/0.1'
```

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

## lawref.process.VALID

*attribute* · *module attribute*

```python
VALID = 'valid_transition'
```

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

## lawref.process.VIOLATING_STATUSES

*attribute* · *module attribute*

```python
VIOLATING_STATUSES = ('VIOLATED', 'CONFLICTED')
```

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

## lawref.process.build_run_report

*function*

```python
def build_run_report(document: dict, journal: dict, budget: int = DEFAULT_BUDGET, procedure_name: str | None = None, resources: dict | None = None) -> dict
```

Прогон журнала дела: кадр на шаг, доступные шаги на последнем кадре.

`resources` — байты, которые журналу не принадлежат и в JSON не пишутся:
сегодня это `calendar_resource_bytes` [§85](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#85-calendar-snapshot), без которых дневной срок
(`add_business_days`) отказывает MISSING_CALENDAR. Ключ набора при этом
остаётся в деле (`case.options.calendarSnapshot`) и входит в caseHash.

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L833-L1355)

## lawref.process.build_static_report

*function*

```python
def build_static_report(document: dict) -> dict
```

Структурный отчёт: автоматы пакета плюс находки верификации.

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

## lawref.process.exit_code

*function*

```python
def exit_code(report: dict) -> int
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L1412-L1413)

## lawref.process.procedures

*function*

```python
def procedures(document: dict) -> list[dict]
```

Автоматы пакета, восстановленные из узлов CLIR.

Порядок — по имени процедуры; состояния и переходы — по id. Байты отчёта
тем самым не зависят от порядка узлов во входе.

[§201.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#2011-узел-procedure-decision-0156) (DECISION-0156): автомат — ДАННЫЕ узла `procedure`; правил
`<P>/initial`, `<P>/<T>/valid`, `<P>/<T>/enters` десугаризация больше не
эмитирует, и узел читается напрямую. Ветка восстановления из правил
остаётся для CLIR, порождённого до S3.

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

## lawref.process.render_text

*function*

```python
def render_text(report: dict) -> str
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L1416-L1419)

## lawref.process.report_bytes

*function*

```python
def report_bytes(report: dict) -> bytes
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L1402-L1403)

## lawref.process.verdict

*function*

```python
def verdict(report: dict) -> str
```

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L1406-L1409)

## lawref.process.verify

*function*

```python
def verify(procedure: dict) -> tuple[list[dict], list[dict]]
```

Находки и заметки по структуре одного автомата: (findings, notes).

[View source](https://github.com-arxohq/arxo-io/law/blob/2edc2b92ce22b52e03f4081d2769a58229684379/engines/lawref/lawref/process.py#L437-L523)
