# lawref.migrate

*module*

Миграции редакций [§32.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#321-операции-поправки)–[§32.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#322-инвариант-консолидации): применение операций поправки (DECISION-0009).

Ребро revision graph [§32](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#32-revision-graph) может нести операции — формализованную дельту
изменяющего акта. Ребро без операций остаётся аннотацией связи; ребро с
операциями обязано удовлетворять инварианту консолидации [§32.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#322-инвариант-консолидации):

    apply(previous, operations) ≡ next

Сравнение ведётся по проекции фрагментов [§29](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#29-alignment-мультиязычных-фрагментов) — множеству пар *(локатор,
язык)* → текст. Инвариант ловит два различных класса дефектов одной
проверкой: ошибку формализации дельты и расхождение официально
опубликованной консолидации с текстом самого изменяющего акта.

Проекция здесь несёт ТЕКСТЫ, а не дайджесты (в отличие от
`entrenchment.edition_projection`): применение обязано класть байты, а не
их хэши. Проверка соответствия этих текстов байтам закреплённой публикации
— отдельная проверка [§194](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#194-sourceprovenance-checks) (`LDC-E5202`), и она настоящей не подменяется;
файловая система здесь не нужна, и функции модуля чистые.

Порядок диагностик — причина раньше следствия. Конфликт операций ([§32.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#321-операции-поправки))
прекращает разбор: где порядок применения не определён, сообщать о
расхождении консолидации значит называть следствие вместо причины. По той
же причине несуществующая цель операции отменяет вывод о расхождении.

Отложено: `renumber` порождает remap-таблицу локаторов для резолюции [§30.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#302-dynamic-reference)
(DECISION-0009, открытый вопрос 2) — здесь операция только применяется к
проекции, а сломанные ею ссылки называются `LDC-E5405`.

## lawref.migrate.CONSOLIDATION_MISMATCH_CODE

*attribute* · *module attribute*

```python
CONSOLIDATION_MISMATCH_CODE = 'LDC-E5401'
```

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

## lawref.migrate.DANGLING_LOCATOR_CODE

*attribute* · *module attribute*

```python
DANGLING_LOCATOR_CODE = 'LDC-E5405'
```

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

## lawref.migrate.MIGRATION_BASE_CODE

*attribute* · *module attribute*

```python
MIGRATION_BASE_CODE = 'LDC-E5404'
```

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

## lawref.migrate.OPERATIONS_OVERLAP_CODE

*attribute* · *module attribute*

```python
OPERATIONS_OVERLAP_CODE = 'LDC-E5403'
```

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

## lawref.migrate.OPERATION_TARGET_CODE

*attribute* · *module attribute*

```python
OPERATION_TARGET_CODE = 'LDC-E5402'
```

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

## lawref.migrate.STRUCTURAL_OPS

*attribute* · *module attribute*

```python
STRUCTURAL_OPS = ('repeal', 'renumber')
```

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

## lawref.migrate.TEXTUAL_OPS

*attribute* · *module attribute*

```python
TEXTUAL_OPS = ('replace', 'insert')
```

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

## lawref.migrate.apply_operations

*function*

```python
def apply_operations(base: dict[tuple[str, str], str], operations: list[dict], edge_effective: str | None = None, revision_id: str = '') -> tuple[dict[tuple[str, str], str], list[dict]]
```

Применение операций к проекции редакции; чистая функция.

Возвращает результат и диагностики `LDC-E5402` — операции, чья цель не
существует (`replace`/`repeal`/`renumber` отсутствующего локатора) либо,
наоборот, уже существует (`insert`). Операция с несуществующей целью
пропускается: применять её не к чему, а домысливать намерение поправки
компилятор не вправе.

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

## lawref.migrate.consolidate

*function*

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

Проекция редакции-результата, вычисленная из основания и операций.

Фаза 1 (DECISION-0009): редакция-результат заводится руками, а функция
служит проверке инварианта [§32.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#322-инвариант-консолидации). Фаза 2 сделает её порождающей — тексты
фрагментов `next` станут производными артефактами.

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

## lawref.migrate.declared_entrenchment_diagnostics

*function*

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

D4 из узлов `entrenchment` [§32.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#323-entrenchment) для одного revision edge.

Entrenchment связан с source work, а revision — с edition; их сопоставление
идёт через `previous` edition. Так защита одной Конституции не может
случайно запретить одноимённый locator другого источника.

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

## lawref.migrate.edition_texts

*function*

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

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

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

## lawref.migrate.ordered_operations

*function*

```python
def ordered_operations(operations: list[dict], edge_effective: str | None) -> list[tuple[str, int, dict]]
```

Порядок применения [§32.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#321-операции-поправки): по возрастанию `effective`, при равенстве —
в порядке объявления. Последовательность самого изменяющего акта
авторитетна, поэтому tie-break — индекс, а не локатор.

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

## lawref.migrate.revision_diagnostics

*function*

```python
def revision_diagnostics(nodes: list[dict], revision_id: str, protected: list[str] | None = None) -> list[dict]
```

Полная проверка ребра [§32.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#321-операции-поправки)–[§32.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#322-инвариант-консолидации); порядок — причина раньше следствия.

Ребро без операций диагностик не порождает: форма 0.1 (аннотация связи)
остаётся действительной, и настоящая проверка её не ужесточает.

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