Skip to content

lawref.mutate

Детерминированные semantic mutations над CLIR.

Модуль намеренно работает с уже lowered Legal IR: он не переписывает .law-исходники и не пытается угадать юридический текст. Каждый дескриптор содержит достаточно данных, чтобы его можно было повторно применить к тому же semantic snapshot через :func:apply_mutation.

Границы v1:

  • перечисление не имеет скрытого лимита; cap действует только когда вызывающий передал его явно и это отражено в manifest;
  • invalid означает, что операция дала бы невалидный CLIR либо нарушила базовую safety-проверку правила; stillborn означает валидный результат с тем же semantic hash. Stillborn — generator-internal/non-score запись, а не mutant, который можно засчитать killed или survived;
  • contentHash меняется только у структурно изменённых узлов. В некоторых legacy-пакетах есть post-lowering attachments с историческим contentHash, и перерасчёт всех узлов превращал бы один mutant в шумный derived diff. Top-level semanticHash пересчитывается всегда.

Это не интерпретатор права. Он применяет только локальные структурные операторы, а корректность формы подтверждает нормативная JSON Schema.

Attributes

NameDescription
COMPARISON_SWAPSNo description.
DEFAULT_OPERATORSNo description.
SCHEMA_VERSIONNo description.

Classes

NameDescription
InvalidMutationA descriptor cannot produce a schema- and safety-valid CLIR mutant.
MutationErrorDescriptor, base document, or caller contract is malformed.

Functions

NameDescription
apply_mutationApply one descriptor to CLIR and return a fresh, rehashed document.
enumerate_mutantsEnumerate valid CLIR mutants in canonical descriptor order.
iter_mutantsЛенивый близнец enumerate_mutants: поток вместо материализации.
report_bytesCanonical, reproducible transport form of an enumeration result.

COMPARISON_SWAPSattributemodule attribute#

COMPARISON_SWAPS = {
  'eq': ('ne', 'ge', 'le'),
  'ne': ('eq'),
  'lt': ('le', 'eq'),
  'le': ('lt', 'eq'),
  'gt': ('ge', 'eq'),
  'ge': ('gt', 'eq')
}

DEFAULT_OPERATORSattributemodule attribute#

DEFAULT_OPERATORS = (
  'drop_conjunct',
  'swap_comparison',
  'substitute_var',
  'bind_entity_ref',
  'freshen_var_occurrence',
  'toggle_not_known',
  'remove_not_known',
  'drop_effective',
  'remove_priority',
  'remove_rule'
)

SCHEMA_VERSIONattributemodule attribute#

SCHEMA_VERSION = 'law.mutate/0.1'

InvalidMutationclass#

class InvalidMutation(MutationError)

Bases: MutationError

A descriptor cannot produce a schema- and safety-valid CLIR mutant.

MutationErrorclass#

class MutationError(ValueError)

Bases: ValueError

Descriptor, base document, or caller contract is malformed.

apply_mutationfunction#

def apply_mutation(document: dict, descriptor: dict) -> dict

Apply one descriptor to CLIR and return a fresh, rehashed document.

The source document is never mutated. Descriptor replay is guarded by the semantic snapshot and each recorded before value, so applying a descriptor to another edition fails loudly rather than drifting to a similarly shaped location. This public entrypoint performs full document preflight and validates the complete resulting document afterwards; bulk enumeration uses the internal preflighted path once for throughput.

enumerate_mutantsfunction#

def enumerate_mutants(document: dict, operators: Iterable[str] | str | None = None, cap: int | None = None, nodes: Iterable[str] | None = None) -> dict[str, Any]

Enumerate valid CLIR mutants in canonical descriptor order.

The return object is intentionally JSON-ready::

{"manifest": ..., "mutants": [{"descriptor": ..., "document": ...}],
"invalid": [...], "stillborn": [...]}.

cap=None means no cap. An explicit cap stops after that many valid mutants in canonical order. The manifest names exactly how many later descriptors were not examined, rather than pretending that cap is an exhaustive result. nodes restricts candidates to the named carrier nodes and is reflected in the manifest; existing callers without it get byte-identical results (реализация — потребитель iter_mutants).

iter_mutantsfunction#

def iter_mutants(document: dict, operators: Iterable[str] | str | None = None, cap: int | None = None, nodes: Iterable[str] | None = None)

Ленивый близнец enumerate_mutants: поток вместо материализации.

Появился из замера профайлера связывания (31.08.2026): на kz-income-tax (16,7 МБ, 1681 правило) жадное перечисление — это 1681 deepcopy полного документа с пересчётом semanticHash каждого, часы и гигабайты ДО первого использования. Поток отдаёт ("valid" | "invalid" | "stillborn", запись) в том же каноническом порядке и с теми же записями, что жадная форма, но держит один мутант за раз; nodes сужает кандидатов по id узла.

report_bytesfunction#

def report_bytes(report: dict) -> bytes

Canonical, reproducible transport form of an enumeration result.

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

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