# lawref.resolver

*module*

Package resolution — инкременты WP-31/WP-35 (SPEC [§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml)–[§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock), [§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла)–[§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility), [§209](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#209-theory-hash-и-artifact-hash)).

Реализовано: разбор `law.toml` (tomllib) в parsed-манифест формы
`package-manifest.schema.json`; каноничность имён пакетов ([§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла), T044: единый
код LDC-E1101 у manifest-/lockfile-ног здесь и source-ноги в lawc
law-hir/resolve.rs); проверка покрытия зависимостей lockfile-ом ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock):
нормативен разрешённый lock); dynamic reference [§30.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#302-dynamic-reference) → exact resolved
edition в manifest.resolvedEditions [§170](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#170-evaluation-input-manifest-и-execution-receipt) (T010); resolve-контекст WP-35 —
content-addressed загрузка зависимостей по lock (dev-layout `deps/`),
exports/`pkg::Symbol` ([§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла)/[§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility), v1-конвенция публичности), envelope.imports
с хэшами пакетов в 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)), линковка замкнутого мира для
межпакетного вывода (ворота — verify/ci/gates/compiler/check_package_resolve.py).

Отложено (перенесено в WP-35 решением DECISION-0030): команда `lawc lock` с
dependency/source diff поверх этого же контекста, registry-протокол вместо
dev-layout, offline-режим сборки ([§243](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/32-part-xxxi-security-and-trust.ru.md#243-network-isolation)). Rust-нога резолюции в law-hir
доехала не вся: `LDC-E1101`–`E1105` и `E1108` там есть, отложены ДВА кода —
`E1106` (транзитивная зависимость вне lock, [§23](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#23-import)) и `E1107` (коллизия StableId
между пакетами, [§14](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/05-part-v-lexis-and-basic-syntax.ru.md#14-идентификаторы)).

## lawref.resolver.DEP_PIN_CODE

*attribute* · *module attribute*

```python
DEP_PIN_CODE = 'LDC-E1104'
```

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

## lawref.resolver.DEV_REGISTRY_ID

*attribute* · *module attribute*

```python
DEV_REGISTRY_ID = 'law-dsl-dev'
```

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

## lawref.resolver.DOCUMENTS_DIR

*attribute* · *module attribute*

```python
DOCUMENTS_DIR = 'resources/documents'
```

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

## lawref.resolver.EXPANSION_PIN_CODE

*attribute* · *module attribute*

```python
EXPANSION_PIN_CODE = 'LDC-E1340'
```

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

## lawref.resolver.EXPORTABLE_KINDS

*attribute* · *module attribute*

```python
EXPORTABLE_KINDS = ('function_decl', 'symbol_decl', 'type_decl', 'fragment', 'rule', 'interpretation', 'deadline_policy', 'temporal_resolution_policy', 'evidence_policy')
```

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

## lawref.resolver.ID_COLLISION_CODE

*attribute* · *module attribute*

```python
ID_COLLISION_CODE = 'LDC-E1107'
```

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

## lawref.resolver.LAYER_DEPENDENCY_CODE

*attribute* · *module attribute*

```python
LAYER_DEPENDENCY_CODE = 'LDC-E8102'
```

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

## lawref.resolver.LAYER_ORDER

*attribute* · *module attribute*

```python
LAYER_ORDER = {'L0': 0, 'L1': 1, 'L2': 2, 'L3': 3}
```

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

## lawref.resolver.PACKAGE_NAME_CODE

*attribute* · *module attribute*

```python
PACKAGE_NAME_CODE = 'LDC-E1101'
```

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

## lawref.resolver.PACKAGE_NAME_RE

*attribute* · *module attribute*

```python
PACKAGE_NAME_RE = re.compile('^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$')
```

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

## lawref.resolver.SNAPSHOTS_DIR

*attribute* · *module attribute*

```python
SNAPSHOTS_DIR = 'resources/snapshots'
```

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

## lawref.resolver.SYMBOL_RESOLVE_CODE

*attribute* · *module attribute*

```python
SYMBOL_RESOLVE_CODE = 'LDC-E1105'
```

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

## lawref.resolver.TRANSITIVE_CODE

*attribute* · *module attribute*

```python
TRANSITIVE_CODE = 'LDC-E1106'
```

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

## lawref.resolver.VERSION_CONFLICT_CODE

*attribute* · *module attribute*

```python
VERSION_CONFLICT_CODE = 'LDC-E1112'
```

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

## lawref.resolver.CalendarResourceError

*class*

```python
class CalendarResourceError(ValueError)
```

Bases: `ValueError`

Отказ оркестрации календарного ресурса DECISION-0110 [§2.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#21-23-примитива-смешивали-уровни-системы).

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

## lawref.resolver.DependencySpec

*class*

```python
class DependencySpec(NamedTuple)
```

Bases: `NamedTuple`

Развёрнутая запись `[dependencies]` [§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml) (errata E-0160).

Значение строки — либо версия-строка, либо таблица
`{version, registry?, features?, optional?}`; обе формы нормативны по
`package-manifest.schema.json` ([§0.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/00-preamble.ru.md#01-нормативные-артефакты-и-порядок-разрешения-расхождений) п. 5), и строковая есть сокращение
таблицы с одним `version`. Развёртка здесь одна на всех потребителей:
до E-0160 каждый читал значение записи как версию, и табличная форма
сравнивалась с закреплённой версией целым объектом.

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

### lawref.resolver.DependencySpec.features

*attribute* · *instance attribute*

```python
features: list[str]
```

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

### lawref.resolver.DependencySpec.optional

*attribute* · *instance attribute*

```python
optional: bool
```

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

### lawref.resolver.DependencySpec.registry

*attribute* · *instance attribute*

```python
registry: str | None
```

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

### lawref.resolver.DependencySpec.version

*attribute* · *instance attribute*

```python
version: str
```

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

## lawref.resolver.canonical_package_name

*function*

```python
def canonical_package_name(name: str) -> bool
```

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

## lawref.resolver.check_lock_coverage

*function*

```python
def check_lock_coverage(manifest: dict, lock: dict) -> list[str]
```

[§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock): canonical build использует exact versions из lock — каждая зависимость
манифеста обязана быть закреплена (имя и точная версия).

Табличная запись [§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml) добавляет три сверки (errata E-0160): названный
издатель против `registryId` закреплённого пакета — только когда lock его
называет (молчание лока об издателе не есть утверждение об ином);
запрошенные возможности против его feature set; `optional = true`
освобождает зависимость от обязательного закрепления, но не от сверок,
если она всё-таки закреплена.

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

## lawref.resolver.check_locked_resources

*function*

```python
def check_locked_resources(root: Path, lock: dict) -> list[str]
```

PAR-007: semantic source edit без lock update останавливает build.

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

## lawref.resolver.check_names

*function*

```python
def check_names(manifest: dict, lock: dict) -> list[str]
```

T044 (часть manifest+lock): неканоничные имена отклоняются согласованно.

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

## lawref.resolver.clir_index

*function*

```python
def clir_index(clir_dir: Path) -> dict[str, Path]
```

Имя пакета → файл `*.lawir.json` каталога CLIR (сканер верхнего уровня,
зеркало `law-cli::imports_context::clir_index`). Канонический JSON держит
`package` после `nodes`, поэтому имя читается с хвоста файла; полный
разбор — только при промахе.

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

## lawref.resolver.content_descriptor

*function*

```python
def content_descriptor(ir: dict) -> dict
```

Registry-дескриптор из реальных байтов пакета (замена placeholder-а
dev_descriptor: contentHash — хэш канонических байтов CLIR).

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

## lawref.resolver.declared_layer

*function*

```python
def declared_layer(manifest: dict) -> str | None
```

Объявленный слой пакета — `[features] semanticLayer` ([§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml)).

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

## lawref.resolver.dependency_spec

*function*

```python
def dependency_spec(value) -> DependencySpec
```

Значение записи `[dependencies]` → развёрнутая запись ([§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml), E-0160).

Типы полей берутся ПО ФОРМЕ, а не приведением: `registry` — только
строка, `optional` — только `true`. Схема манифеста требует ровно этого,
но `check_lock_coverage` зовут и на несхемных словарях (векторы, ворота),
а приведение здесь разошлось бы с портом, где `as_str`/`as_bool` тоже
отвергают чужой тип. Байтовый контракт держится формой, не догадкой.

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

## lawref.resolver.dev_descriptor

*function*

```python
def dev_descriptor(name: str, version: str, namespace: str) -> dict
```

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

## lawref.resolver.diff_lock

*function*

```python
def diff_lock(old: dict, new: dict) -> list[str]
```

Dependency diff ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock): обновление lock сопровождается diff-ом).

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

## lawref.resolver.discover_documents

*function*

```python
def discover_documents(root: Path) -> list[Path]
```

Документы дела: каждый файл в `resources/documents/**` при корне пакета
(DECISION-0165 [§1.12](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#1-что-сохраняется-без-изменений)). Скрытые файлы (`.DS_Store`, `.gitkeep`) — не
документы: они попадают в каталог помимо автора и ломали бы лок у каждого,
кто открыл папку. Порядок — по пути.

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

## lawref.resolver.discover_resources

*function*

```python
def discover_resources(root: Path) -> list[dict]
```

Детерминированно найти ресурсы пакета и построить записи law.lock 0.2:
A3 sources (compile_time), оверлеи меток [§218](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/30-part-xxix-ux-dx-specification.ru.md#218-multilingual-ux) (presentation,
DECISION-0069) и документы дела [§168.4](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1684-пакет-дело-и-операция-ask-decision-0165) (evidence, DECISION-0165 [§1.12](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#1-что-сохраняется-без-изменений):
`id` — `document:<путь внутри resources/documents/>`, `contentHash` —
sha256 точных байтов). Оверлеи ищутся ТОЛЬКО в `i18n/` при корне пакета — rglob
здесь ловил бы одноимённые каталоги внутри закреплённых байтов
`sources/`, которые пакету не принадлежат.

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

## lawref.resolver.discover_snapshots

*function*

```python
def discover_snapshots(root: Path) -> list[Path]
```

`export.json` каждого снимка при корне пакета, в порядке имён.

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

## lawref.resolver.effective_layer

*function*

```python
def effective_layer(manifest: dict, registry: dict[tuple[str, str], dict]) -> str | None
```

Эффективный слой сборки для lockfile: максимум по корню и зависимостям.

None — если слой не объявлен ни у корня, ни у одной зависимости: пустое
поле честнее выдуманного `L0`.

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

## lawref.resolver.envelope_imports

*function*

```python
def envelope_imports(context: dict) -> list[dict]
```

LockedImport-ы для envelope.imports корневого CLIR ([§209](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#209-theory-hash-и-artifact-hash): semantic hash
покрывает хэши импортированных пакетов). Порядок — по имени пакета.

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

## lawref.resolver.expansion_context

*function*

```python
def expansion_context(root: Path) -> tuple[list[dict], list[dict]]
```

Контекст `--expansions` для компилятора: записи lock с абсолютным `root`.

Возвращает (контекст, диагностики). Алиас манифеста без записи в lock,
запись lock без алиаса, расхождение name/version/contentHash с байтами
каталога — `LDC-E1340` ([§279.1.8](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/39-part-xxxvii-open-issues-0-2.ru.md#27918-пакет-определения-и-пин)); «ближайшая версия» не выбирается.

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

## lawref.resolver.expansion_pins

*function*

```python
def expansion_pins(root: Path, manifest: dict) -> list[dict]
```

Записи секции `expansions` law.lock по `[expansions]` манифеста: пакет
определения читается по `path` (от корня потребителя), `contentHash` —
digest значимых файлов (`lawref.expansion.pack_content_hash`).

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

## lawref.resolver.export_bases

*function*

```python
def export_bases(ir: dict) -> dict[str, str]
```

Надтипы публичных сущностей пакета: local name → StableId базы ([§42](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#42-subtyping)).

Errata E-0121: `lawc check` ведёт цепь подтипов [§42](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/08-part-viii-type-system.ru.md#42-subtyping) через границу пакета
только по тому, что предъявил резолвер, — иначе два разных чужих имени
(должник закона о банкротстве, лицо ГК) для статики несравнимы. Считает,
как и `exports`, только оракул; в `envelope.imports` ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)/[§209](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#209-theory-hash-и-artifact-hash)) не
переносится — это checking aid resolve-контекста, не семантика
потребителя. Сущность без базы записи не имеет: у компилятора «предъявлен
пакет, записи нет» и означает «надтипа нет».

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

## lawref.resolver.export_constants

*function*

```python
def export_constants(ir: dict) -> dict[str, dict]
```

E-0162: объявленные типы публичных констант из закреплённого CLIR.

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

## lawref.resolver.export_entity_types

*function*

```python
def export_entity_types(ir: dict) -> list[str]
```

E-0162: номинальные типы для контекстного entity_ref в value<T>.

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

## lawref.resolver.export_kinds

*function*

```python
def export_kinds(ir: dict) -> dict[str, str]
```

Public local name → CLIR node kind for a pinned dependency.

Ordinary `pkg::Symbol` needs only the public export table.  A qualified
`@source(pkg::Fragment)` has a stronger contract: a relation or function
with the same public spelling must never be accepted as a source-text
anchor.  This map is therefore passed to the compiler as non-semantic
resolve-context evidence alongside `exports`; it is reconstructed from
the same pinned CLIR bytes and never travels in `envelope.imports`.

Enum variants have no own node.  They remain ordinary exports for the
expression resolver and are marked `enum_variant` here so they cannot
masquerade as fragments.

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

## lawref.resolver.export_relation_parameter_names

*function*

```python
def export_relation_parameter_names(ir: dict) -> dict[str, list[str]]
```

DECISION-0186: source parameter names, separate from E-0162 types.

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

## lawref.resolver.export_relation_parameters

*function*

```python
def export_relation_parameters(ir: dict) -> dict[str, list[dict]]
```

E-0162: сигнатуры публичных отношений, принимающих value-позиции.

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

## lawref.resolver.export_source_fragments

*function*

```python
def export_source_fragments(ir: dict) -> dict[str, dict]
```

Закреплённое evidence для публичного fragment в импортированном ``@source``.

Запись возникает только у public fragment со структурной связью с
source_edition и собственным documentHash. Повреждённый text-record
отбрасывает весь fragment. package contentHash отсутствует намеренно:
он не заменяет хэш редакции или текста.

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

## lawref.resolver.exports

*function*

```python
def exports(ir: dict) -> dict[str, str]
```

Публичные символы пакета: local name → StableId ([§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла) `pkg::Symbol`).

[§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility): по умолчанию declaration является `internal`, и межпакетная ссылка на
него запрещена. В CLIR это поле `visibility: "public"` (пишется только для
`pub`-деклараций — умолчание не пишется, чтобы поле было аддитивным [§209](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#209-theory-hash-и-artifact-hash)).
До DECISION-0011 здесь действовала конвенция «экспортируется всё, у чего
есть `#`»: `pub` не доезжал до CLIR, и различать было нечего.

Local name — часть StableId после `#`; узлы без `#` не адресуемы извне.

Член публичного перечисления экспортируется ВМЕСТЕ СО СВОИМ ТИПОМ ([§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility),
errata E-0065). Собственного узла у члена нет — `type_decl` несёт их
списком имён в `variants` ([§55.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/09-part-ix-values-terms-expressions.ru.md#551-match-expression)), — поэтому запись синтезируется:
`{namespace}#{Член}`, ровно тот StableId, каким лоуверится локальная
ссылка на член. До E-0065 экспортировался только тип, и `pub enum` был
декларацией без употребления: `check` ссылку на член принимал, `lower`
отвергал её LDC-E1105.

Порядок двухпроходный, и это не вкус: имя члена, совпавшее с именем
публичной ДЕКЛАРАЦИИ того же пакета, не вправе её вытеснить. У узла id
может быть переопределён `@id(...)` ([§14](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/05-part-v-lexis-and-basic-syntax.ru.md#14-идентификаторы)) и тогда отличается от
`{namespace}#{имя}`; синтезированная запись назвала бы StableId, которого
в мире нет.

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

## lawref.resolver.fact_groups

*function*

```python
def fact_groups(ir: dict) -> dict[str, list[dict]]
```

Публичные факт-группы пакета ([§23.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#231-экспортируемые-факт-группы-аддитивно-decision-0069), DECISION-0069): имя группы →
её assertion-узлы, отсортированные по id.

Носитель членства — provenance узла (`factGroup`, `visibility`), а не
поле visibility: у Assertion в схеме его нет, и это тот же род носителя,
каким A3 метит свои узлы (`a3Kind`). Считает состав ТОЛЬКО оракул — как
exports [§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility) (E-0065): компилятор потребителя материализует то, что ему
предъявили, и своего мнения о составе не имеет. Непубличные группы
наружу не выдаются: включение `facts pkg::Группа;` на них падает.

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

## lawref.resolver.find_package_root

*function*

```python
def find_package_root(start: Path) -> Path | None
```

Ближайший вверх каталог с law.toml; файл начинает поиск с родителя.

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

## lawref.resolver.generate_lock

*function*

```python
def generate_lock(manifest: dict, registry: dict[tuple[str, str], dict], resources: list[dict] | None = None, expansions: list[dict] | None = None, imports: dict[str, list[tuple[str, str]]] | None = None, *, library=None, profile_block: dict | None = None, root_imports: list[tuple[str, str]] | None = None) -> dict
```

Разрешение манифеста в канонический law.lock ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)): exact versions,
packages отсортированы по canonical identity, resolutionHash — derived-хэш
без самого себя; generated-at/compiler build не включаются ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)).

`imports` — известные импорты закреплённых пакетов (`имя → [(имя,
версия)…]`, из envelope `imports` их CLIR): лок закрепляет ТРАНЗИТИВНОЕ
замыкание импортов корня, как того требует мир `ask` (DECISION-0165 [§1.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#1-что-сохраняется-без-изменений),
`LDC-E1358`/`LDC-E1106`), с ребром от импортёра к импортируемому.
Транзитивная зависимость обязательна: реестр без неё — отказ. Без
`imports` (реестр без сведений об импортах) закрепляются прямые
зависимости — прежние байты.

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

## lawref.resolver.import_closure

*function*

```python
def import_closure(manifest: dict, packages: dict[str, dict]) -> set[str]
```

Транзитивное замыкание импортов корня по загруженным снимкам зависимостей
(старт — строки `[dependencies]` манифеста; зеркало
`law_resolver::context::import_closure`). Достигнутое, но не загруженное
имя в замыкание входит — так подготовка ask видит нематериализованное C.

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

## lawref.resolver.layer_diagnostics

*function*

```python
def layer_diagnostics(manifest: dict, registry: dict[tuple[str, str], dict]) -> list[dict]
```

`LDC-E8102`: зависимость объявляет слой выше собственного пакета.

Зависимость без объявленного слоя пропускается молча: её слой неизвестен, а
выдумывать «L0 по умолчанию» значило бы утверждать то, чего никто не
проверял. Отсутствие объявления у КОРНЯ тоже не диагностируется — слой
необязателен (LS [§2.5](https://github.com/arxohq/law/blob/master/spec/LAYERS-SURFACES.ru.md#25-объявление-и-вывод-слоя)), проверяется только заявленное.

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

## lawref.resolver.link_world

*function*

```python
def link_world(root_ir: dict, context: dict) -> tuple[list[dict], list[dict]]
```

Замкнутый мир программы для evaluation: узлы корня + узлы зависимостей
(порядок: корень, затем зависимости по имени — детерминизм [§211](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/29-part-xxviii-compiler-pipeline.ru.md#211-determinism)).
Коллизия StableId между пакетами — ошибка ([§14](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/05-part-v-lexis-and-basic-syntax.ru.md#14-идентификаторы): id уникален глобально).
Пины внутри мира сверяет `world_pin_diagnostics` (errata E-0123).

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

## lawref.resolver.load_package_context

*function*

```python
def load_package_context(root: Path) -> dict
```

Загрузка и проверка resolve-контекста корня пакета (dev-layout выше).

Возвращает {"manifest", "lock", "packages": {name: ir}, "exports":
{name: {local: StableId}}, "exportKinds": {name: {local: kind}},
"diagnostics": [...]}; диагностики — ошибки
контекста (пиннинг/замкнутость), содержимое пакетов с ошибками не
считается загруженным.

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

## lawref.resolver.load_registry

*function*

```python
def load_registry(registry_dir: Path) -> dict[tuple[str, str], dict]
```

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

## lawref.resolver.locked_dependencies

*function*

```python
def locked_dependencies(manifest: dict) -> list[tuple[str, DependencySpec]]
```

Зависимости манифеста, которые закрепляет `law.lock` ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)).

Пакеты прелюдии `law.std.*` (errata E-0154, DECISION-0166 [§4.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#4-не-цели-01)) сюда не
входят: словарь std приходит с версией семантики языка, реестра и
content-адреса у него нет, и строка `[dependencies]` с ним — только
подтверждение пина (сверяется компилятором с `import`, LDC-E1111), а не
зависимость для закрепления. Имена и слои (`name_diagnostics`,
`layer_diagnostics`) читают манифест целиком — там std остаётся
обычной строкой.

Значение записи отдаётся РАЗВЁРНУТЫМ (`DependencySpec`, errata E-0160):
закрепляется версия, а не форма, которой её записал автор.

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

## lawref.resolver.lowering_imports

*function*

```python
def lowering_imports(context: dict) -> list[dict]
```

Resolve context consumed by `lawc lower --imports`.

`envelope_imports` intentionally contains only normative LockedImport
data, because it becomes part of the consumer's semantic hash.  The
compiler additionally needs resolver evidence to enforce [§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility) and the
fragment-only contract of cross-package `@source`; exports and kinds are
derived from the already hash-pinned dependency bytes and are omitted when
CLIR is emitted again.

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

## lawref.resolver.name_diagnostics

*function*

```python
def name_diagnostics(manifest: dict | None, lock: dict | None) -> list[dict]
```

T044: диагностики неканоничных имён с каноническим кодом ([§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла)/[§199](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#199-diagnostic-code-ranges)).

Возвращает [{code, severity, surface, message}]; surface — какая нога
валидации отклонила (manifest | lockfile); None пропускает ногу.
Source-нога живёт в lawc (law-hir/resolve.rs) и эмитит ТОТ ЖЕ код —
согласованность трёх ног проверяет вектор T044 (режим resolve).

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

## lawref.resolver.package_content_hash

*function*

```python
def package_content_hash(ir: dict) -> str
```

Content-хэш пакета: sha256 канонических байтов CLIR-документа ([§208](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/28-part-xxvii-canonical-legal-ir.ru.md#208-canonical-serialization)).
Именно он пиннится в law.lock и в envelope.imports потребителей.

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

## lawref.resolver.package_root_for_locked_resource

*function*

```python
def package_root_for_locked_resource(laws_root: Path, resource_id: str, content_hash: str | None = None) -> Path | None
```

Найти детерминированный package-root потребителя закреплённого ресурса.

Порождаемый официальный календарь KZ не имеет собственного source-пакета:
его runtime-байты закрепляют локи использующих календарь актов. Поэтому
MCP deadline ищет один из таких локов по id (и ожидаемому datasetHash), а
окончательную schema/type/hash-проверку всё равно делает
:func:`resolve_calendar_resource`.

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

## lawref.resolver.package_root_for_namespace

*function*

```python
def package_root_for_namespace(laws_root: Path, namespace: str) -> Path | None
```

Найти package-root по нормативному namespace манифеста [§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml).

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

## lawref.resolver.parse_manifest

*function*

```python
def parse_manifest(law_toml_bytes: bytes) -> dict
```

`law.toml` → parsed manifest ([§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml)); валидность — по package-manifest.schema.

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

## lawref.resolver.plain_descriptor

*function*

```python
def plain_descriptor(desc: dict) -> dict
```

Плоская запись пакета в локе (без `registryId`/`resolverUri`): имя,
версия, namespace, contentHash, отсортированные features — форма
`sync_calendar_locks` и локов пакетов-дел (зеркало `lawc --plain-descriptors`).

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

## lawref.resolver.registry_for_library

*function*

```python
def registry_for_library(library, clir_dir: Path, *, plain: bool = True) -> tuple[dict[tuple[str, str], dict], dict[str, list[tuple[str, str]]]]
```

Реестр и карта импортов для ВСЕЙ развёртки профиля B (DECISION-0170
[§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)) из каталога CLIR: каждый элемент B обязан найтись той же четвёркой,
а его `imports` — лежать в B (замкнутость [§170.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1701-профиль-канона-decision-0170)).

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

## lawref.resolver.registry_from_clir

*function*

```python
def registry_from_clir(manifest: dict, clir_dir: Path, *, plain: bool = True) -> tuple[dict[tuple[str, str], dict], dict[str, list[tuple[str, str]]]]
```

Реестр и карта импортов для `generate_lock` из каталога CLIR: прямые
зависимости манифеста и — транзитивно — импорты их CLIR (envelope
`imports[].package`). Зеркало `lawc lock --clir` (DECISION-0165 [§1.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#1-что-сохраняется-без-изменений)).

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

## lawref.resolver.resolve

*function*

```python
def resolve(law_toml_path: Path, lock_path: Path) -> dict
```

Полная проверка пары manifest+lock; возвращает parsed manifest либо ValueError.

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

## lawref.resolver.resolve_calendar_resource

*function*

```python
def resolve_calendar_resource(root: Path, ir: dict, case: dict) -> bytes | None
```

Прочитать календарь по `law.lock` и сверить оба digest-а ([§85](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#85-calendar-snapshot)).

`root` — package-root либо любой путь внутри пакета. Относительный `path`
лока может выходить к общему `corpus/clir` (DECISION-0110, В1), но байты
всё равно принимаются только при совпадении `contentHash` строки лока и
`datasetHash` выбранного узла.

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

## lawref.resolver.resolve_dynamic_references

*function*

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

[§30.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#302-dynamic-reference): каждый узел kind=reference разрешается в ровно одно source_edition,
применимое на legal_time; результат — {reference.id: edition.id} для
manifest.resolvedEditions ([§170](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#170-evaluation-input-manifest-и-execution-receipt)), плюс записи резолюции для proof-узлов
`source_resolution` [§182](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/26-part-xxv-proof-graph-and-explanations.ru.md#182-source-resolution-proof). Ошибки — fatal issues ДО вычисления:

- SOURCE_RESOLUTION_FAILED — ни одного применимого edition ([§30.2](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/07-part-vii-source-and-document-model.ru.md#302-dynamic-reference):
  dynamic reference ДОЛЖНА разрешиться в static);
- SOURCE_RESOLUTION_AMBIGUOUS — несколько distinguishable source states
  на выбранный момент ([§198](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/27-part-xxvi-static-semantics-and-diagnostics.ru.md#198-diagnostic-format)-prose), либо granularity legal_time и
  lifecycle-границ различаются без TemporalResolutionPolicy ([§82](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#82-temporal-axes)/[§2.15](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/01-part-i-audit.ru.md#215-legal_time-date-было-слишком-узким)).

**Отвергнутые кандидаты собираются, а не выбрасываются** ([§182](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/26-part-xxv-proof-graph-and-explanations.ru.md#182-source-resolution-proof)): без них
proof резолюции говорит «взята эта редакция» и молчит о том, какие ещё
рассматривались и почему не подошли, — а именно этот вопрос задаёт
`why-not` («источник не действовал»). Причина отклонения — состояние
редакции на момент (`closed | not_yet | suspended`), то же, что считает
`edition_state`; выдумывать здесь нечего.

Детерминизм: узлы и кандидаты обходятся в порядке ir.nodes.

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

## lawref.resolver.resolve_symbol

*function*

```python
def resolve_symbol(context: dict, package: str, local_name: str) -> tuple[str | None, list[dict]]
```

`pkg::Symbol` → StableId по exports контекста ([§22](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#22-заголовок-файла)/[§24](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#24-visibility)).

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

## lawref.resolver.schemas_load_and_validate_lock

*function*

```python
def schemas_load_and_validate_lock(lock_path: Path) -> dict
```

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

## lawref.resolver.selected_calendar_snapshot

*function*

```python
def selected_calendar_snapshot(ir: dict, case: dict) -> dict | None
```

Тот же выбор [§85](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/12-part-xii-events-actions-temporal-model.ru.md#85-calendar-snapshot), что у движков; неоднозначность оставляется движку.

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

## lawref.resolver.world_pin_diagnostics

*function*

```python
def world_pin_diagnostics(parts: list[tuple[str, dict]]) -> list[dict]
```

Пины ВНУТРИ собранного мира (errata E-0123).

`link_deps` сверяет contentHash только тех зависимостей, которые ей
передали аргументами, — то есть прямых. Пин между двумя ЗАВИСИМОСТЯМИ не
сверял никто: мир, где акт B понижен против `std@0.2.0`, а узлы в мире от
`std@0.1.0`, исполнялся молча и давал вывод по чужой версии (проба ромба
DECISION-0112 [§5.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/02-part-ii-goals-and-scope.ru.md#51-no-hidden-defaults), 04.09.2026).

Проверяется НЕ замкнутость: мир корпуса намеренно неполон — потребитель,
который читает у соседа только ТИПЫ (алиасы хаба лиц), не обязан тащить
его узлы. Проверяется совпадение: если импортируемый пакет в мире ЕСТЬ,
его байты обязаны быть теми, на которых потребитель понижен.

Вторая проверка — две версии одного пакета в одном мире: сегодня их ловит
коллизия StableId [§14](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/05-part-v-lexis-and-basic-syntax.ru.md#14-идентификаторы), но сообщение говорит об id, а не о причине.

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