lawref.query.facts
Реификация CLIR в плоские отношения LawQL (DECISION-0079, Ф1).
Виды верхнеуровневых узлов извлекаются из нормативной JSON Schema. Поэтому
новый вид нельзя молча потерять: документ с видом, которого схема не объявила,
отвергается LDC-Q1001, а схема одновременно публикуется через --schema.
Attributes
| Name | Description |
|---|---|
DEFAULT_CORPUS | No description. |
DEFAULT_SCHEMA | No description. |
RELATION_FIELDS | No description. |
ROOT | No description. |
Classes
| Name | Description |
|---|---|
FactStore | No description. |
Functions
| Name | Description |
|---|---|
discover_corpus | No description. |
load_corpus | Снимок корпуса в FactStore. |
peek_package | package документа по его байтам — без разбора 0,5 МБ узлов. |
peek_package_name | Read package.name with the same conservative fast path as before. |
schema_node_kinds | Все допустимые Node, а не все вложенные term/formula kinds. |
DEFAULT_CORPUSattributemodule attribute#
DEFAULT_CORPUS = ROOT / 'corpus/clir'DEFAULT_SCHEMAattributemodule attribute#
DEFAULT_SCHEMA = ROOT / 'spec/schema/legal-ir.schema.json'RELATION_FIELDSattributemodule attribute#
RELATION_FIELDS: dict[str, tuple[str, ...]] = {
'nodes': ('id', 'kind', 'package', 'package_name', 'path'),
'edges': ('from', 'to', 'role', 'package', 'path'),
'anchors': ('node', 'anchor', 'act', 'locator', 'package', 'path'),
'labels': ('node', 'lang', 'text', 'status', 'package'),
'positions': ('norm', 'kind', 'bearer_type', 'package', 'path'),
'windows': ('norm', 'kind', 'deadline', 'package', 'path'),
'imports': ('package', 'imported', 'semantic_hash', 'path'),
'fields': ('node', 'field', 'value', 'value_kind', 'package', 'path'),
'literals': ('node', 'context', 'predicate', 'polarity', 'package', 'path'),
'variables': ('node', 'context', 'name', 'type', 'package', 'path'),
'rules': (
'id',
'strength',
'head_predicate',
'head_polarity',
'head_variables',
'body_variables',
'body_predicates',
'package',
'path'
),
'norms': ('id', 'modality', 'goal_kind', 'condition_predicates', 'package', 'path'),
'interpretations': ('id', 'predicate', 'role', 'package', 'path')
}ROOTattributemodule attribute#
ROOT = Path(__file__).resolve().parents[4]FactStoreclassdataclass#
class FactStore(relations: dict[str, list[dict]] = lambda : {name: [] for name in RELATION_FIELDS}(), documents: list[dict] = list(), node_kinds: tuple[str, ...] = schema_node_kinds(), node_count: int = 0, enabled_relations: set[str] = lambda : set(RELATION_FIELDS)(), _by_id: dict[str, dict] = dict(), _doc_by_package: dict[str, dict] = dict(), _parameter_owners: dict[str, str] = dict())documentsattributeclass attributeinstance attribute#
documents: list[dict] = field(default_factory=list)enabled_relationsattributeclass attributeinstance attribute#
enabled_relations: set[str] = field(default_factory=lambda : set(RELATION_FIELDS))node_countattributeclass attributeinstance attribute#
node_count: int = 0node_kindsattributeclass attributeinstance attribute#
node_kinds: tuple[str, ...] = field(default_factory=schema_node_kinds)relationsattributeclass attributeinstance attribute#
relations: dict[str, list[dict]] = field(default_factory=lambda : {name: [] for name in RELATION_FIELDS})add_documentmethod#
def add_document(document: dict, path: Path, law_path: str | None = None) -> Nonedocumentmethod#
def document(package: str) -> dict | Nonefinalizemethod#
def finalize() -> Nonenodemethod#
def node(node_id: str) -> dict | Nonerowsmethod#
def rows(relation: str, package_glob: str = '*') -> list[dict]schemamethod#
def schema() -> dictdiscover_corpusfunction#
def discover_corpus(corpus: Path = DEFAULT_CORPUS) -> list[Path]load_corpusfunction#
def load_corpus(paths: Iterable[Path] | None = None, package_glob: str = '*', relations: Iterable[str] | None = None, package_globs: Iterable[str] | None = None, include_law_paths: bool = True, documents: Iterable[tuple[Path | str, dict]] | None = None) -> FactStoreСнимок корпуса в FactStore.
Два входа, взаимоисключающие: paths — файлы CLIR (по умолчанию весь
corpus/clir), documents — пары (путь, уже разобранный CLIR) от хоста,
который держит корпус в памяти (каталог MCP: те же документы, сверенные по
stat за миллисекунды, вместо второго чтения и разбора 184 МБ на каждый
вызов). Путь при документе нужен ровно тем, чем и при файле: порядком
обхода (первый в канонической сортировке — единственный снимок пакета) и
полем path строк фактов; байты результата от входа не зависят — это
держит check_query.py. Документы не копируются и не мутируются: строки
фактов ссылаются на их узлы, поэтому хост обязан отдавать их разделяемыми
и неизменяемыми (у каталога MCP это уже контракт corpus_snapshot).
Глоб пакета применяется ДО разбора, когда путь известен: имя подглядывается
в байтах (peek_package_name), и файл вне глоба не разбирается вовсе.
Следствие, названное честно: испорченный CLIR ВНЕ глоба запрос больше не
роняет — его целостность держат ворота компилятора, а не LawQL.
peek_packagefunction#
def peek_package(data: bytes) -> dict | Nonepackage документа по его байтам — без разбора 0,5 МБ узлов.
Точность, а не эвристика. Метка содержит неэкранированные кавычки, а
внутри JSON-строки " обязана быть \", поэтому каждое вхождение метки
в валидном JSON — ключ package, чьё значение начинается с ключа name.
Берётся ПОСЛЕДНЕЕ вхождение, и { + хвост разбирается как объект: разбор
удаётся тогда и только тогда, когда вхождение стоит на глубине 1 — вложенное
закрыло бы больше скобок, чем открыло (imports[].package в канонических
байтах и так раньше top-level: ключи отсортированы). Дубликат top-level
ключа json.loads берёт последним — как и rfind. Документ с whitespace
(не канонический, вроде отформатированных календарных CLIR) метки не
содержит и честно уходит в полный разбор: None означает «не знаю», а не
«нет пакета».
Замер 02.09.2026 на 376 файлах / 183 МБ: чтение байтов 0,31 с, 369 подглядываний 0,003 с против 2,2 с json.loads всего корпуса.
peek_package_namefunction#
def peek_package_name(data: bytes) -> str | NoneRead package.name with the same conservative fast path as before.
schema_node_kindsfunction#
def schema_node_kinds(schema_path: Path = DEFAULT_SCHEMA) -> tuple[str, ...]Все допустимые Node, а не все вложенные term/formula kinds.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.