# lawref.entrenchment

*module*

Неизменяемое ядро источника: diff редакций и entrenchment-констрейнт (D4).

Механика для норм вида «положения X изменению не подлежат» (Конституция РК
ст. 2.7 при порядке изменения ст. 92–93; аналогично — eternity clauses иных
правопорядков). Формализуется НЕ как правило вывода, а как статическая
проверка над парой редакций одного `source_work` ([§32](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#32-revision-graph) revision graph):
защищённые фрагменты обязаны совпадать байтово, иначе поправка неправомерна
независимо от соблюдения процедуры.

Реализовано: проекция редакции в {(locator, language): digest} по фрагментам
[§29](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#29-alignment-мультиязычных-фрагментов) (объявленный `contentHash` текста; при отсутствии — sha256 самих байтов,
та же конвенция, что у гейта [§194](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#194-sourceprovenance-checks)), трёхсторонний diff редакций
(changed/added/removed) и констрейнт «защищённое множество ∩ изменённое = ∅»
с диагностикой `LDC-E5301`. Защита задаётся ДАННЫМИ (список локаторов), а не
кодом: перечень неизменяемых положений — часть пакета, а не компилятора.

Отложено: связывание с amendment-power ([§127](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/18-part-xvii-normative-positions.ru.md#127-power)) — поправка как исполняемая
процедура (этап 5 карты KZ-CONSTITUTION-AUDIT); сравнение редакций на разных
языках между собой (здесь языки сопоставляются попарно, дивергенция kk/ru —
предмет [§158](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/21-part-xx-interpretations-and-theories.ru.md#158-conflicting-official-texts)/D3).

## lawref.entrenchment.ENTRENCHED_CHANGED_CODE

*attribute* · *module attribute*

```python
ENTRENCHED_CHANGED_CODE = 'LDC-E5301'
```

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

## lawref.entrenchment.check_entrenched_changes

*function*

```python
def check_entrenched_changes(diff: dict[str, list[dict]], protected: list[str], target: str) -> list[dict]
```

Констрейнт неизменяемого ядра над УЖЕ вычисленным множеством изменений.

Отделено от `check_entrenchment` ради [§32.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#322-инвариант-консолидации): множество затронутых
положений может приходить не только из diff-а двух готовых редакций, но и
из операций поправки — и тогда проверка выполняется ДО применения, а
диагностика адресует конкретную операцию конкретного акта (DECISION-0009
[§4](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#4-не-цели-01) п. 8). Формулировки сообщений общие для обоих путей: они входят в
байтовый контракт и правятся только вместе.

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

## lawref.entrenchment.check_entrenchment

*function*

```python
def check_entrenchment(nodes: list[dict], edition_a: str, edition_b: str, protected: list[str]) -> list[dict]
```

Констрейнт неизменяемого ядра: защищённое ∩ изменённое = ∅.

Возвращает список диагностик `LDC-E5301` (по одной на затронутое
положение, порядок детерминирован diff-ом). Пустой список означает, что
поправка не затрагивает ядра — но НЕ что она правомерна: соблюдение
процедуры [§92](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/13-part-xiii-context-scope-applicability.ru.md#92-edition-applicability)–93 проверяется отдельно и здесь не подразумевается.

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

## lawref.entrenchment.diff_editions

*function*

```python
def diff_editions(nodes: list[dict], edition_a: str, edition_b: str) -> dict[str, list[dict]]
```

Трёхсторонний diff редакций по фрагментам; порядок детерминирован.

`changed` — локатор есть в обеих редакциях, но байты текста различаются;
`added`/`removed` — присутствует только в одной. Все три класса значимы
для entrenchment: изъятие защищённого положения — тоже его изменение.

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

## lawref.entrenchment.edition_projection

*function*

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

Редакция → {(locator, language): digest} по её фрагментам ([§29](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#29-alignment-мультиязычных-фрагментов)).

Ключ — пара локатора и языка: у одной редакции статья существует в
нескольких аутентичных языках (ст. 9), и изменение любого из них есть
изменение положения.

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