# lawref.profiles

*module*

Профили канона [§170.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1701-профиль-канона-decision-0170) (DECISION-0170) — эталон.

Профиль — именованный, датированный и хэшированный состав библиотеки норм:
не пакет и не дело, а перечень с версиями и хэшами, сам закреплённый
`contentHash`. Здесь: чтение артефакта `law.profile/0.1`, развёртка B
(объединение `packages[]` и вложенных профилей, транзитивно, с конфликтами
вместо слияния), замкнутость по `imports` CLIR, записи `LockedPackage`
из элементов B, граница `[dependencies]` ([§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml), `LDC-E1366`), сверка лока с
библиотекой ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock), `LDC-E1367`) и строка `jurisdictionProfile` ([§168.3](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1683-единый-типизированный-evaluationrequest)).

Множества B/L/C/W [§168.4](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1684-пакет-дело-и-операция-ask-decision-0165): профиль — граница библиотеки, НЕ состав мира.
Лок закрепляет всю развёртку B; исполняется замыкание фактических импортов
корня C; закреплённый, но не импортированный пакет в мир не входит.

## lawref.profiles.BOUNDARY_CODE

*attribute* · *module attribute*

```python
BOUNDARY_CODE = 'LDC-E1366'
```

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

## lawref.profiles.CLIR_HEAD_CACHE_DIR

*attribute* · *module attribute*

```python
CLIR_HEAD_CACHE_DIR = schemas.cache_dir() / 'clir-heads'
```

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

## lawref.profiles.DEPS_SUBDIR

*attribute* · *module attribute*

```python
DEPS_SUBDIR = ('deps', 'profiles')
```

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

## lawref.profiles.KEYS

*attribute* · *module attribute*

```python
KEYS = {'packages': 'name', 'profiles': 'id', 'calendars': 'node', 'expansions': 'name'}
```

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

## lawref.profiles.PROFILE_CODE

*attribute* · *module attribute*

```python
PROFILE_CODE = 'LDC-E1367'
```

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

## lawref.profiles.QUAD

*attribute* · *module attribute*

```python
QUAD = ('name', 'version', 'namespace', 'contentHash')
```

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

## lawref.profiles.SCHEMA_VERSION

*attribute* · *module attribute*

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

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

## lawref.profiles.STRING_RE

*attribute* · *module attribute*

```python
STRING_RE = re.compile('^(?P<id>[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)*)/(?P<version>[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?)#(?P<hash>sha256:[0-9a-f]{64})$')
```

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

## lawref.profiles.Library

*class*

```python
class Library
```

Развёртка B(P): множества по ключам; конфликт — `LDC-E1367`.

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

### lawref.profiles.Library.calendars

*attribute* · *instance attribute*

```python
calendars: dict[str, dict] = {}
```

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

### lawref.profiles.Library.expansions

*attribute* · *instance attribute*

```python
expansions: dict[str, dict] = {}
```

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

### lawref.profiles.Library.language

*attribute* · *instance attribute*

```python
language: str | None = None
```

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

### lawref.profiles.Library.packages

*attribute* · *instance attribute*

```python
packages: dict[str, dict] = {}
```

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

### lawref.profiles.Library.profiles

*attribute* · *instance attribute*

```python
profiles: dict[str, dict] = {}
```

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

### lawref.profiles.Library.semantics_revision

*attribute* · *instance attribute*

```python
semantics_revision: str | None = None
```

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

### lawref.profiles.Library.names

*method*

```python
def names() -> set[str]
```

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

## lawref.profiles.ProfileError

*class*

```python
class ProfileError(ValueError)
```

Bases: `ValueError`

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

### lawref.profiles.ProfileError.code

*attribute* · *instance attribute*

```python
code = code
```

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

### lawref.profiles.ProfileError.message

*attribute* · *instance attribute*

```python
message = message
```

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

## lawref.profiles.artifact_path

*function*

```python
def artifact_path(root: Path, profile_id: str, version: str) -> Path
```

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

## lawref.profiles.boundary_problems

*function*

```python
def boundary_problems(manifest: dict, library: Library) -> list[str]
```

`[dependencies]` при профиле: каждая строка — пакет B той же версии,
издатель и возможности согласны; `optional` границы не расширяет;
прелюдия `law.std` исключена ([§10](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#10-lawtoml), `LDC-E1366`).

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

## lawref.profiles.clir_head

*function*

```python
def clir_head(path: Path) -> dict
```

Шапка CLIR по байтам файла: `{"package": {"name": …}, "imports": …}`.

Файл вне JSON — `ValueError`, как у `json.loads` всего документа
(вызывающий решает: индекс пропускает файл, загрузка B отказывает).

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

## lawref.profiles.closure_problems

*function*

```python
def closure_problems(library: Library, clir_for: Callable[[str], dict | None]) -> list[str]
```

Замкнутость [§170.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1701-профиль-канона-decision-0170): `imports` CLIR каждого пакета B лежат в B по всей четвёрке.

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

## lawref.profiles.content_hash

*function*

```python
def content_hash(artifact: dict) -> str
```

sha256 канонических байтов артефакта БЕЗ поля `contentHash` (нерекурсивно).

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

## lawref.profiles.default_clir_dir

*function*

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

`corpus/clir` ближайшего корня вверх от пакета (зеркало
`imports_context::default_clir_dir`): реестр CLIR авторского дерева, из
которого читается B \ C — закреплённое, но не материализованное (П14).

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

## lawref.profiles.deps_label

*function*

```python
def deps_label(profile_id: str, version: str) -> str
```

Имя артефакта в сообщениях: путь ОТ КОРНЯ пакета, а не абсолютный путь
хоста, — как у снимков [§168.5](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1685-композиция-сведений-дел-decision-0169) (`compose.read_export`). Конверт отказа
входит в голдены векторов и не вправе зависеть от каталога checkout
([§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/profiles.py#L75-L80)

## lawref.profiles.deps_loader

*function*

```python
def deps_loader(root: Path) -> Callable[[str, str, str], dict]
```

Вложенные профили — из `deps/profiles/<id>/<version>/profile.json`.

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

## lawref.profiles.dir_label

*function*

```python
def dir_label(profile_id: str, version: str) -> str
```

То же для каталога-реестра профилей (`--profiles <dir>`): путь от него.

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

## lawref.profiles.dir_loader

*function*

```python
def dir_loader(profiles_dir: Path) -> Callable[[str, str, str], dict]
```

Профили из каталога-реестра `<dir>/<id>/<version>/profile.json`.

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

## lawref.profiles.expand

*function*

```python
def expand(artifact: dict, loader: Callable[[str, str, str], dict]) -> Library
```

B(P) — транзитивно по `profiles[]`; `loader(id, version, contentHash)`
возвращает вложенный артефакт (уже прочитанный `read_profile`).

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

## lawref.profiles.import_problems

*function*

```python
def import_problems(root_imports_: list[tuple[str, str]], library: Library) -> list[str]
```

[§23](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/06-part-vi-package-and-module-system.ru.md#23-import) под профилем: версия `import` точная и равна пину B (`LDC-E1110`).

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

## lawref.profiles.load_for_root

*function*

```python
def load_for_root(root: Path, manifest: dict, lock: dict | None) -> tuple[dict, dict, Library]
```

Артефакт, блок `{id, version, contentHash, registryId?}` и развёртка B
для корня с `[profile]`; лок, если предъявлен, сверяется блоком.

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

## lawref.profiles.lock_problems

*function*

```python
def lock_problems(lock: dict, library: Library, block: dict) -> list[str]
```

[§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock): L = B по четвёрке; блок `profile` лока = профиль; линия языка и
ревизия семантики — те же, что у лока; календари и развёртки лока — из
перечней профиля.

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

## lawref.profiles.locked_packages

*function*

```python
def locked_packages(library: Library) -> list[dict]
```

Записи `LockedPackage` исчерпывающего состава из элементов B ([§11](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/04-part-iv-project-and-files.ru.md#11-lawlock)).

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

## lawref.profiles.parse_string

*function*

```python
def parse_string(text) -> dict | None
```

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

## lawref.profiles.profile_string

*function*

```python
def profile_string(block: dict) -> str
```

`"<id>/<version>#sha256:…"` — строка поля [§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) из блока профиля лока.

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

## lawref.profiles.quadruple

*function*

```python
def quadruple(item: dict) -> tuple
```

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

## lawref.profiles.read_profile

*function*

```python
def read_profile(path: Path, label: str | None = None) -> dict
```

Артефакт по схеме, с сошедшимся `contentHash` и множествами в каноническом порядке.

`label` — имя артефакта в сообщениях (см. `deps_label`); без него берётся
предъявленный путь, каким его назвал вызывающий.

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

## lawref.profiles.registry_loader

*function*

```python
def registry_loader(root: Path, present: dict[str, dict]) -> Callable[[str], dict | None]
```

CLIR пакета B: из deps/ (материализованное C), иначе из реестра
`corpus/clir` авторского дерева по имени пакета; нет нигде — None.

Из файла читается только шапка (`clir_head`): замкнутость [§170.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1701-профиль-канона-decision-0170) судит
по `imports`, и дерево узлов ей не нужно.

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

## lawref.profiles.root_imports

*function*

```python
def root_imports(root: Path) -> list[tuple[str, str]]
```

`import`-декларации заголовков `.law` корня (без прелюдии `law.std.*`):
старт обхода C и корневые рёбра лока, доступные до понижения ([§168.4](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/24-part-xxiii-cases-snapshots-evaluation.ru.md#1684-пакет-дело-и-операция-ask-decision-0165)).

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