# lawref.approvals

*module*

Контур утверждений B1 — WP-26 (LAYERS-SURFACES [§3.6](https://github.com/arxohq/law/blob/master/spec/LAYERS-SURFACES.ru.md#36-привязка-утверждения); DECISION-0006).

Юрист утверждает **блок ревью-документа**, а не пакет и не файл. Запись
утверждения привязывает блок к паре хэшей:

- `subjectSemanticHash` — semantic hash узла ([§209](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#209-theory-hash-и-artifact-hash)-фильтр, применённый к узлу):
  что именно подписано по смыслу;
- `verbalizationHash` — sha256 байтов вербализованного блока: что именно
  подписано по тексту.

Расхождение любой из них переводит утверждение в `stale` (`LDC-E8202`), и это
две РАЗНЫЕ причины: «подписан другой смысл» и «подписан другой текст». Юристу
нужно видеть, какая именно — от этого зависит, нужен ли повторный разбор нормы
или достаточно перечитать формулировку.

Границы, вытекающие из errata E-0010: правка метки НЕ меняет semantic hash
узла, поэтому наполнение меток даёт `stale_verbalization`, а не
`stale_semantics`. Правка соседней нормы не трогает ни то, ни другое —
утверждение остаётся действительным.

Здесь нет часов: `at` — данные о человеческом действии, они приходят
параметром (FND [§6](https://github.com/arxohq/law/blob/master/spec/FOUNDATION.ru.md) запрещает ambient clock в семантическом пути).

Язык — ось утверждения, а не его свойство (DECISION-0032): запись несёт
`language`, и утверждения на разных языках независимы. Черновой pack
(`reviewStatus: draft`) утверждать статусом выше `draft` нельзя — та же форма
отказа, что у блока с маркером [§3.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#3-цели-law-dsl-core-01), и по той же причине: подписывать
формулировку, которую никто не выверил, значит подписывать неизвестное.

## lawref.approvals.APPROVING_STATUS

*attribute* · *module attribute*

```python
APPROVING_STATUS = 'approved'
```

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

## lawref.approvals.CURRENT

*attribute* · *module attribute*

```python
CURRENT = 'current'
```

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

## lawref.approvals.ORPHANED

*attribute* · *module attribute*

```python
ORPHANED = 'orphaned'
```

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

## lawref.approvals.SCHEMA_VERSION

*attribute* · *module attribute*

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

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

## lawref.approvals.STALE_APPROVAL

*attribute* · *module attribute*

```python
STALE_APPROVAL = 'LDC-E8202'
```

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

## lawref.approvals.STALE_SEMANTICS

*attribute* · *module attribute*

```python
STALE_SEMANTICS = 'stale_semantics'
```

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

## lawref.approvals.STALE_VERBALIZATION

*attribute* · *module attribute*

```python
STALE_VERBALIZATION = 'stale_verbalization'
```

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

## lawref.approvals.STATUSES

*attribute* · *module attribute*

```python
STATUSES = ('draft', 'reviewed', 'verified', 'approved', 'disputed')
```

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

## lawref.approvals.check_approval

*function*

```python
def check_approval(approval: dict, document: dict, verbalization: dict) -> dict
```

Сверка утверждения с текущими программой и вербализацией.

Возвращает `{"state", "subjectId", "reason"?, "expected"?, "actual"?}`.
`state` — один из `current` / `stale_semantics` / `stale_verbalization` /
`orphaned`. Смена версии pack сама по себе устареванием НЕ является: [§3.6](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#3-цели-law-dsl-core-01)
привязывает утверждение к тексту, и если текст не изменился, подписано
ровно то же самое.

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

## lawref.approvals.make_approval

*function*

```python
def make_approval(node: dict, block: dict, pack: dict, reviewer: str, at: str, document: dict | None = None, status: str = APPROVING_STATUS, note: str | None = None) -> dict
```

Запись утверждения по узлу CLIR и его блоку вербализации.

`block` — элемент `verbalize(...)["blocks"]`. Блок с маркером тотальности
(`LDC-E8201`) утвердить статусом выше `draft` нельзя: юрист подписал бы
текст, в котором семантика спрятана (LS [§3.3](https://github.com/arxohq/law/blob/master/spec/LAYERS-SURFACES.ru.md#33-тотальность-и-честные-пробелы)).

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

## lawref.approvals.review_queue

*function*

```python
def review_queue(approvals: list[dict], document: dict, verbalization: dict) -> list[dict]
```

Очередь повторного ревью: диагностики `LDC-E8202` по устаревшим записям.

Порядок — по `subjectId`: очередь детерминирована и сравнима между
прогонами ([§211](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/29-part-xxviii-compiler-pipeline.ru.md#211-determinism) в духе, хотя сама очередь семантикой не является).

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

## lawref.approvals.summary

*function*

```python
def summary(approvals: list[dict], document: dict, verbalization: dict) -> dict[str, Any]
```

Сводка по пакету: сколько блоков утверждено, сколько устарело, сколько
не утверждено вовсе. Нужна отчёту о покрытии [§33.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#331-formalization-coverage) и дашборду плана [§9](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#9-стандартная-структура-проекта).

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

## lawref.approvals.verified_ready

*function*

```python
def verified_ready(node_id: str, approvals: list[dict], document: dict, verbalization: dict, language: str | None = None) -> bool
```

Выполнено ли необходимое условие [§33.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#331-formalization-coverage) для перехода фрагмента в VERIFIED.

Необходимое, а не достаточное: [§33.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#331-formalization-coverage) требует ещё технических и
conformance-проверок. Здесь проверяется ровно юридическая половина —
есть действующее утверждение статуса `approved` на нужном языке.

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