Skip to content

lawref.resolver

Package resolution — инкременты WP-31/WP-35 (SPEC §10–§11, §22–§24, §209).

Реализовано: разбор law.toml (tomllib) в parsed-манифест формы package-manifest.schema.json; каноничность имён пакетов (§22, T044: единый код LDC-E1101 у manifest-/lockfile-ног здесь и source-ноги в lawc law-hir/resolve.rs); проверка покрытия зависимостей lockfile-ом (§11: нормативен разрешённый lock); dynamic reference §30.2 → exact resolved edition в manifest.resolvedEditions §170 (T010); resolve-контекст WP-35 — content-addressed загрузка зависимостей по lock (dev-layout deps/), exports/pkg::Symbol (§22/§24, v1-конвенция публичности), envelope.imports с хэшами пакетов в semantic hash (§209), линковка замкнутого мира для межпакетного вывода (ворота — verify/ci/gates/compiler/check_package_resolve.py).

Отложено (перенесено в WP-35 решением DECISION-0030): команда lawc lock с dependency/source diff поверх этого же контекста, registry-протокол вместо dev-layout, offline-режим сборки (§243). Rust-нога резолюции в law-hir доехала не вся: LDC-E1101–E1105 и E1108 там есть, отложены ДВА кода — E1106 (транзитивная зависимость вне lock, §23) и E1107 (коллизия StableId между пакетами, §14).

Attributes

NameDescription
DEP_PIN_CODENo description.
DEV_REGISTRY_IDNo description.
DOCUMENTS_DIRNo description.
EXPANSION_PIN_CODENo description.
EXPORTABLE_KINDSNo description.
ID_COLLISION_CODENo description.
LAYER_DEPENDENCY_CODENo description.
LAYER_ORDERNo description.
PACKAGE_NAME_CODENo description.
PACKAGE_NAME_RENo description.
SNAPSHOTS_DIRNo description.
SYMBOL_RESOLVE_CODENo description.
TRANSITIVE_CODENo description.
VERSION_CONFLICT_CODENo description.

Classes

NameDescription
CalendarResourceErrorОтказ оркестрации календарного ресурса DECISION-0110 §2.1.
DependencySpecРазвёрнутая запись [dependencies] §10 (errata E-0160).

Functions

NameDescription
canonical_package_nameNo description.
check_lock_coverage§11: canonical build использует exact versions из lock — каждая зависимость
check_locked_resourcesPAR-007: semantic source edit без lock update останавливает build.
check_namesT044 (часть manifest+lock): неканоничные имена отклоняются согласованно.
clir_indexИмя пакета → файл *.lawir.json каталога CLIR (сканер верхнего уровня,
content_descriptorRegistry-дескриптор из реальных байтов пакета (замена placeholder-а
declared_layerОбъявленный слой пакета — [features] semanticLayer (§10).
dependency_specЗначение записи [dependencies] → развёрнутая запись (§10, E-0160).
dev_descriptorNo description.
diff_lockDependency diff (§11: обновление lock сопровождается diff-ом).
discover_documentsДокументы дела: каждый файл в resources/documents/** при корне пакета
discover_resourcesДетерминированно найти ресурсы пакета и построить записи law.lock 0.2:
discover_snapshotsexport.json каждого снимка при корне пакета, в порядке имён.
effective_layerЭффективный слой сборки для lockfile: максимум по корню и зависимостям.
envelope_importsLockedImport-ы для envelope.imports корневого CLIR (§209: semantic hash
expansion_contextКонтекст --expansions для компилятора: записи lock с абсолютным root.
expansion_pinsЗаписи секции expansions law.lock по [expansions] манифеста: пакет
export_basesНадтипы публичных сущностей пакета: local name → StableId базы (§42).
export_constantsE-0162: объявленные типы публичных констант из закреплённого CLIR.
export_entity_typesE-0162: номинальные типы для контекстного entity_ref в value<T>.
export_kindsPublic local name → CLIR node kind for a pinned dependency.
export_relation_parameter_namesDECISION-0186: source parameter names, separate from E-0162 types.
export_relation_parametersE-0162: сигнатуры публичных отношений, принимающих value-позиции.
export_source_fragmentsЗакреплённое evidence для публичного fragment в импортированном @source.
exportsПубличные символы пакета: local name → StableId (§22 pkg::Symbol).
fact_groupsПубличные факт-группы пакета (§23.1, DECISION-0069): имя группы →
find_package_rootБлижайший вверх каталог с law.toml; файл начинает поиск с родителя.
generate_lockРазрешение манифеста в канонический law.lock (§11): exact versions,
import_closureТранзитивное замыкание импортов корня по загруженным снимкам зависимостей
layer_diagnosticsLDC-E8102: зависимость объявляет слой выше собственного пакета.
link_worldЗамкнутый мир программы для evaluation: узлы корня + узлы зависимостей
load_package_contextЗагрузка и проверка resolve-контекста корня пакета (dev-layout выше).
load_registryNo description.
locked_dependenciesЗависимости манифеста, которые закрепляет law.lock (§11).
lowering_importsResolve context consumed by lawc lower --imports.
name_diagnosticsT044: диагностики неканоничных имён с каноническим кодом (§22/§199).
package_content_hashContent-хэш пакета: sha256 канонических байтов CLIR-документа (§208).
package_root_for_locked_resourceНайти детерминированный package-root потребителя закреплённого ресурса.
package_root_for_namespaceНайти package-root по нормативному namespace манифеста §10.
parse_manifestlaw.toml → parsed manifest (§10); валидность — по package-manifest.schema.
plain_descriptorПлоская запись пакета в локе (без registryId/resolverUri): имя,
registry_for_libraryРеестр и карта импортов для ВСЕЙ развёртки профиля B (DECISION-0170
registry_from_clirРеестр и карта импортов для generate_lock из каталога CLIR: прямые
resolveПолная проверка пары manifest+lock; возвращает parsed manifest либо ValueError.
resolve_calendar_resourceПрочитать календарь по law.lock и сверить оба digest-а (§85).
resolve_dynamic_references§30.2: каждый узел kind=reference разрешается в ровно одно source_edition,
resolve_symbolpkg::Symbol → StableId по exports контекста (§22/§24).
schemas_load_and_validate_lockNo description.
selected_calendar_snapshotТот же выбор §85, что у движков; неоднозначность оставляется движку.
world_pin_diagnosticsПины ВНУТРИ собранного мира (errata E-0123).

DEP_PIN_CODEattributemodule attribute#

DEP_PIN_CODE = 'LDC-E1104'

DEV_REGISTRY_IDattributemodule attribute#

DEV_REGISTRY_ID = 'law-dsl-dev'

DOCUMENTS_DIRattributemodule attribute#

DOCUMENTS_DIR = 'resources/documents'

EXPANSION_PIN_CODEattributemodule attribute#

EXPANSION_PIN_CODE = 'LDC-E1340'

EXPORTABLE_KINDSattributemodule attribute#

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

ID_COLLISION_CODEattributemodule attribute#

ID_COLLISION_CODE = 'LDC-E1107'

LAYER_DEPENDENCY_CODEattributemodule attribute#

LAYER_DEPENDENCY_CODE = 'LDC-E8102'

LAYER_ORDERattributemodule attribute#

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

PACKAGE_NAME_CODEattributemodule attribute#

PACKAGE_NAME_CODE = 'LDC-E1101'

PACKAGE_NAME_REattributemodule attribute#

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

SNAPSHOTS_DIRattributemodule attribute#

SNAPSHOTS_DIR = 'resources/snapshots'

SYMBOL_RESOLVE_CODEattributemodule attribute#

SYMBOL_RESOLVE_CODE = 'LDC-E1105'

TRANSITIVE_CODEattributemodule attribute#

TRANSITIVE_CODE = 'LDC-E1106'

VERSION_CONFLICT_CODEattributemodule attribute#

VERSION_CONFLICT_CODE = 'LDC-E1112'

CalendarResourceErrorclass#

class CalendarResourceError(ValueError)

Bases: ValueError

Отказ оркестрации календарного ресурса DECISION-0110 §2.1.

DependencySpecclass#

class DependencySpec(NamedTuple)

Bases: NamedTuple

Развёрнутая запись [dependencies] §10 (errata E-0160).

Значение строки — либо версия-строка, либо таблица {version, registry?, features?, optional?}; обе формы нормативны по package-manifest.schema.json (§0.1 п. 5), и строковая есть сокращение таблицы с одним version. Развёртка здесь одна на всех потребителей: до E-0160 каждый читал значение записи как версию, и табличная форма сравнивалась с закреплённой версией целым объектом.

featuresattributeinstance attribute#

features: list[str]

optionalattributeinstance attribute#

optional: bool

registryattributeinstance attribute#

registry: str | None

versionattributeinstance attribute#

version: str

canonical_package_namefunction#

def canonical_package_name(name: str) -> bool

check_lock_coveragefunction#

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

§11: canonical build использует exact versions из lock — каждая зависимость манифеста обязана быть закреплена (имя и точная версия).

Табличная запись §10 добавляет три сверки (errata E-0160): названный издатель против registryId закреплённого пакета — только когда lock его называет (молчание лока об издателе не есть утверждение об ином); запрошенные возможности против его feature set; optional = true освобождает зависимость от обязательного закрепления, но не от сверок, если она всё-таки закреплена.

check_locked_resourcesfunction#

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

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

check_namesfunction#

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

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

clir_indexfunction#

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

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

content_descriptorfunction#

def content_descriptor(ir: dict) -> dict

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

declared_layerfunction#

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

Объявленный слой пакета — [features] semanticLayer (§10).

dependency_specfunction#

def dependency_spec(value) -> DependencySpec

Значение записи [dependencies] → развёрнутая запись (§10, E-0160).

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

dev_descriptorfunction#

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

diff_lockfunction#

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

Dependency diff (§11: обновление lock сопровождается diff-ом).

discover_documentsfunction#

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

Документы дела: каждый файл в resources/documents/** при корне пакета (DECISION-0165 §1.12). Скрытые файлы (.DS_Store, .gitkeep) — не документы: они попадают в каталог помимо автора и ломали бы лок у каждого, кто открыл папку. Порядок — по пути.

discover_resourcesfunction#

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

Детерминированно найти ресурсы пакета и построить записи law.lock 0.2: A3 sources (compile_time), оверлеи меток §218 (presentation, DECISION-0069) и документы дела §168.4 (evidence, DECISION-0165 §1.12: id — document:<путь внутри resources/documents/>, contentHash — sha256 точных байтов). Оверлеи ищутся ТОЛЬКО в i18n/ при корне пакета — rglob здесь ловил бы одноимённые каталоги внутри закреплённых байтов sources/, которые пакету не принадлежат.

discover_snapshotsfunction#

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

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

effective_layerfunction#

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

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

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

envelope_importsfunction#

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

LockedImport-ы для envelope.imports корневого CLIR (§209: semantic hash покрывает хэши импортированных пакетов). Порядок — по имени пакета.

expansion_contextfunction#

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

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

Возвращает (контекст, диагностики). Алиас манифеста без записи в lock, запись lock без алиаса, расхождение name/version/contentHash с байтами каталога — LDC-E1340 (§279.1.8); «ближайшая версия» не выбирается.

expansion_pinsfunction#

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

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

export_basesfunction#

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

Надтипы публичных сущностей пакета: local name → StableId базы (§42).

Errata E-0121: lawc check ведёт цепь подтипов §42 через границу пакета только по тому, что предъявил резолвер, — иначе два разных чужих имени (должник закона о банкротстве, лицо ГК) для статики несравнимы. Считает, как и exports, только оракул; в envelope.imports (§11/§209) не переносится — это checking aid resolve-контекста, не семантика потребителя. Сущность без базы записи не имеет: у компилятора «предъявлен пакет, записи нет» и означает «надтипа нет».

export_constantsfunction#

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

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

export_entity_typesfunction#

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

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

export_kindsfunction#

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.

export_relation_parameter_namesfunction#

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

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

export_relation_parametersfunction#

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

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

export_source_fragmentsfunction#

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

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

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

exportsfunction#

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

Публичные символы пакета: local name → StableId (§22 pkg::Symbol).

§24: по умолчанию declaration является internal, и межпакетная ссылка на него запрещена. В CLIR это поле visibility: "public" (пишется только для pub-деклараций — умолчание не пишется, чтобы поле было аддитивным §209). До DECISION-0011 здесь действовала конвенция «экспортируется всё, у чего есть #»: pub не доезжал до CLIR, и различать было нечего.

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

Член публичного перечисления экспортируется ВМЕСТЕ СО СВОИМ ТИПОМ (§24, errata E-0065). Собственного узла у члена нет — type_decl несёт их списком имён в variants (§55.1), — поэтому запись синтезируется: {namespace}#{Член}, ровно тот StableId, каким лоуверится локальная ссылка на член. До E-0065 экспортировался только тип, и pub enum был декларацией без употребления: check ссылку на член принимал, lower отвергал её LDC-E1105.

Порядок двухпроходный, и это не вкус: имя члена, совпавшее с именем публичной ДЕКЛАРАЦИИ того же пакета, не вправе её вытеснить. У узла id может быть переопределён @id(...) (§14) и тогда отличается от {namespace}#{имя}; синтезированная запись назвала бы StableId, которого в мире нет.

fact_groupsfunction#

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

Публичные факт-группы пакета (§23.1, DECISION-0069): имя группы → её assertion-узлы, отсортированные по id.

Носитель членства — provenance узла (factGroup, visibility), а не поле visibility: у Assertion в схеме его нет, и это тот же род носителя, каким A3 метит свои узлы (a3Kind). Считает состав ТОЛЬКО оракул — как exports §24 (E-0065): компилятор потребителя материализует то, что ему предъявили, и своего мнения о составе не имеет. Непубличные группы наружу не выдаются: включение facts pkg::Группа; на них падает.

find_package_rootfunction#

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

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

generate_lockfunction#

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): exact versions, packages отсортированы по canonical identity, resolutionHash — derived-хэш без самого себя; generated-at/compiler build не включаются (§11).

imports — известные импорты закреплённых пакетов (имя → [(имя, версия)…], из envelope imports их CLIR): лок закрепляет ТРАНЗИТИВНОЕ замыкание импортов корня, как того требует мир ask (DECISION-0165 §1.2, LDC-E1358/LDC-E1106), с ребром от импортёра к импортируемому. Транзитивная зависимость обязательна: реестр без неё — отказ. Без imports (реестр без сведений об импортах) закрепляются прямые зависимости — прежние байты.

import_closurefunction#

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

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

layer_diagnosticsfunction#

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

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

Зависимость без объявленного слоя пропускается молча: её слой неизвестен, а выдумывать «L0 по умолчанию» значило бы утверждать то, чего никто не проверял. Отсутствие объявления у КОРНЯ тоже не диагностируется — слой необязателен (LS §2.5), проверяется только заявленное.

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

Замкнутый мир программы для evaluation: узлы корня + узлы зависимостей (порядок: корень, затем зависимости по имени — детерминизм §211). Коллизия StableId между пакетами — ошибка (§14: id уникален глобально). Пины внутри мира сверяет world_pin_diagnostics (errata E-0123).

load_package_contextfunction#

def load_package_context(root: Path) -> dict

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

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

load_registryfunction#

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

locked_dependenciesfunction#

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

Зависимости манифеста, которые закрепляет law.lock (§11).

Пакеты прелюдии law.std.* (errata E-0154, DECISION-0166 §4.3) сюда не входят: словарь std приходит с версией семантики языка, реестра и content-адреса у него нет, и строка [dependencies] с ним — только подтверждение пина (сверяется компилятором с import, LDC-E1111), а не зависимость для закрепления. Имена и слои (name_diagnostics, layer_diagnostics) читают манифест целиком — там std остаётся обычной строкой.

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

lowering_importsfunction#

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 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.

name_diagnosticsfunction#

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

T044: диагностики неканоничных имён с каноническим кодом (§22/§199).

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

package_content_hashfunction#

def package_content_hash(ir: dict) -> str

Content-хэш пакета: sha256 канонических байтов CLIR-документа (§208). Именно он пиннится в law.lock и в envelope.imports потребителей.

package_root_for_locked_resourcefunction#

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.

package_root_for_namespacefunction#

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

Найти package-root по нормативному namespace манифеста §10.

parse_manifestfunction#

def parse_manifest(law_toml_bytes: bytes) -> dict

law.toml → parsed manifest (§10); валидность — по package-manifest.schema.

plain_descriptorfunction#

def plain_descriptor(desc: dict) -> dict

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

registry_for_libraryfunction#

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) из каталога CLIR: каждый элемент B обязан найтись той же четвёркой, а его imports — лежать в B (замкнутость §170.1).

registry_from_clirfunction#

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).

resolvefunction#

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

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

resolve_calendar_resourcefunction#

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

Прочитать календарь по law.lock и сверить оба digest-а (§85).

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

resolve_dynamic_referencesfunction#

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

§30.2: каждый узел kind=reference разрешается в ровно одно source_edition, применимое на legal_time; результат — {reference.id: edition.id} для manifest.resolvedEditions (§170), плюс записи резолюции для proof-узлов source_resolution §182. Ошибки — fatal issues ДО вычисления:

  • SOURCE_RESOLUTION_FAILED — ни одного применимого edition (§30.2: dynamic reference ДОЛЖНА разрешиться в static);
  • SOURCE_RESOLUTION_AMBIGUOUS — несколько distinguishable source states на выбранный момент (§198-prose), либо granularity legal_time и lifecycle-границ различаются без TemporalResolutionPolicy (§82/§2.15).

Отвергнутые кандидаты собираются, а не выбрасываются (§182): без них proof резолюции говорит «взята эта редакция» и молчит о том, какие ещё рассматривались и почему не подошли, — а именно этот вопрос задаёт why-not («источник не действовал»). Причина отклонения — состояние редакции на момент (closed | not_yet | suspended), то же, что считает edition_state; выдумывать здесь нечего.

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

resolve_symbolfunction#

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

pkg::Symbol → StableId по exports контекста (§22/§24).

schemas_load_and_validate_lockfunction#

def schemas_load_and_validate_lock(lock_path: Path) -> dict

selected_calendar_snapshotfunction#

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

Тот же выбор §85, что у движков; неоднозначность оставляется движку.

world_pin_diagnosticsfunction#

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, 04.09.2026).

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

Вторая проверка — две версии одного пакета в одном мире: сегодня их ловит коллизия StableId §14, но сообщение говорит об id, а не о причине.

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.