Skip to content

lawref.query.facts

Реификация CLIR в плоские отношения LawQL (DECISION-0079, Ф1).

Виды верхнеуровневых узлов извлекаются из нормативной JSON Schema. Поэтому новый вид нельзя молча потерять: документ с видом, которого схема не объявила, отвергается LDC-Q1001, а схема одновременно публикуется через --schema.

Attributes

NameDescription
DEFAULT_CORPUSNo description.
DEFAULT_SCHEMANo description.
RELATION_FIELDSNo description.
ROOTNo description.

Classes

NameDescription
FactStoreNo description.

Functions

NameDescription
discover_corpusNo description.
load_corpusСнимок корпуса в FactStore.
peek_packagepackage документа по его байтам — без разбора 0,5 МБ узлов.
peek_package_nameRead 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 = 0

node_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) -> None

documentmethod#

def document(package: str) -> dict | None

finalizemethod#

def finalize() -> None

nodemethod#

def node(node_id: str) -> dict | None

rowsmethod#

def rows(relation: str, package_glob: str = '*') -> list[dict]

schemamethod#

def schema() -> dict

discover_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 | None

package документа по его байтам — без разбора 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 | None

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