# lawref.fuzz

*module*

Фаззер кейсов — L8.1, работа О-4 плана LAYERS-NEXT.

Сидированная генерация типизированных case-входов по объявлениям пакета и
прогон существующего движка над случайными мирами. Оркестрация без семантики
(инвариант №5): модуль строит входы хелперами authoring, зовёт `evaluate`
через `impact.run_scenario` и читает витрину — proof-граф [§180](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/26-part-xxv-proof-graph-and-explanations.ru.md#180-rule-application-proof)/[§135](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/19-part-xviii-norm-lifecycle-fulfillment-violation.ru.md#135-activation) для
покрытия (мера DECISION-0019, вариант C) и отчёты [§115](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#115-конфликтный-результат) для конфликтов.

Цели поиска v1:

- **покрытие**: правило, доказанно применившееся хотя бы в одном мире,
  получает минимизированный сценарий-тест (формат О-1: {"case", "query"},
  query — ground-вывод самого применения); правило, не применившееся ни в
  одном из миров, называется непокрытым — динамическая недостижимость,
  которой статический `norm-statics` не видит;
- **неожиданный CONFLICTED**: миры строятся консистентными по входу (не
  больше одной полярности на атом), поэтому непустой `conflicts` [§115](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/16-part-xv-defeasible-semantics-and-conflict-resolution.ru.md#115-конфликтный-результат) —
  всегда конфликт ПРАВИЛ, не входов; находка минимизируется до сценария;
- **отказы**: pre-evaluation исключение на сгенерированном входе — находка
  отдельного вида.

Скалярные значения (остаток v1, закрыт 27.08.2026): для типа параметра, под
который в САМОМ документе встречаются value-термы (правые части comparison
[§65](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/10-part-x-propositions-and-four-valued-support.ru.md#65-status-tests), окна, константы), пул строится из этих добытых значений — правила с
гардами «== / >= порога» становятся достижимыми, потому что порог и есть
значение из документа. Тип без единого value-терма получает entity_ref, как
раньше (живые кейсы делают так же: `accused(x: Text)` в T033 несёт
entity_ref). Строгие неравенства с непредставленными в документе значениями
остаются недостижимыми честно — соседние значения не синтезируются
(арифметика по типам была бы семантикой в инструменте).

Константы документа (остаток, закрытый 30.08.2026): добываются так же, но
ТОЛЬКО в направленном режиме и только из обратного замыкания самой цели.
Гард `entered_state(v, AmTor)` требует `const_ref` на объявленное состояние,
и синтетическая сущность не совпадёт с ним никогда — из-за этого профиль
процедуры [§160](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/22-part-xxi-procedures.ru.md#160-procedure-declaration) не покрывался ни у одного пакета корпуса. В слепом режиме
пулы остались синтетическими НАМЕРЕННО: глобальная добыча выбирает константу
произвольно и вытесняет капом `MAX_GROUNDINGS` уже работающие подстановки
(замер: −2423 подстановки у 84 пакетов из 157).

Контрпримеры к декларируемым инвариантам (цель «в» эскиза, закрыта
27.08.2026): инвариант пакета — constraint [§93.1](https://github.com/arxohq/law/blob/master/spec/SPEC.ru/14-part-xiii-a-non-derivational-constraints.ru.md#931-назначение) (necessary-направление
определения: antecedent верен ТОЛЬКО ЕСЛИ requirement). Поиск — направленные
миры над обратным замыканием предикатов констрейнта; контрпример = мир, где
движок отвечает antecedent TRUE_ONLY, а какой-то конъюнкт requirement — НЕ
TRUE_ONLY. Оба статуса читаются truth-запросами, сам констрейнт нигде не
вычисляется (инвариант №5: сравниваются выходы движка). Requirement сложнее
конъюнкции литералов/established — назван в manifest.skippedConstraints.

Не входит (горизонт плана): последовательности событий — реализованы
отдельным инструментом L8.2 (`lawref.loophole`, DECISION-0035).

PRNG — hash-DRBG sha256(seed:counter): `import random` в lawref запрещён
линтом детерминизма, и это правильно — сид входит в манифест отчёта, и
прогон с тем же сидом обязан быть байтово воспроизводим.

Shrinking детерминирован и PRNG не трогает: (0) срез по зависимостям —
одним прогоном выбрасываются утверждения предикатов, не достижимых назад от
тела целевого правила через головы промежуточных, затем (1) ddmin
(complement-вариант delta debugging, O(n log n) прогонов против O(n²) у
жадного). При исчерпании гранулярности результат 1-минимален; бюджет
SHRINK_BUDGET — общий на минимизацию.

Направленная генерация (`targeted`): для каждого непокрытого правила миры
строятся только над его релевантными входами (обратное замыкание тела);
попытка 0 — плотная, все ground-атомы положительно и без расхода PRNG
(максимум шансов конъюнкции), дальнейшие — сидированные вариации с
пропусками и отрицаниями (пути через not_known и defeater).

## lawref.fuzz.CONSTRAINTS_CAP

*attribute* · *module attribute*

```python
CONSTRAINTS_CAP = 8
```

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

## lawref.fuzz.FIXED_CONTEXT

*attribute* · *module attribute*

```python
FIXED_CONTEXT = {'legalTime': '2026-01-01', 'timezone': 'UTC', 'decisionTime': '2026-01-01T00:00:00+00:00', 'knowledgeTime': '2026-01-01T00:00:00+00:00'}
```

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

## lawref.fuzz.MAX_GROUNDINGS

*attribute* · *module attribute*

```python
MAX_GROUNDINGS = 8
```

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

## lawref.fuzz.POOL_SIZE

*attribute* · *module attribute*

```python
POOL_SIZE = 2
```

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

## lawref.fuzz.SCALAR_POOL

*attribute* · *module attribute*

```python
SCALAR_POOL = 3
```

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

## lawref.fuzz.SCHEMA_VERSION

*attribute* · *module attribute*

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

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

## lawref.fuzz.SHRINK_BUDGET

*attribute* · *module attribute*

```python
SHRINK_BUDGET = 200
```

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

## lawref.fuzz.TARGET_CONST_POOL

*attribute* · *module attribute*

```python
TARGET_CONST_POOL = 24
```

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

## lawref.fuzz.WORLD_CAP

*attribute* · *module attribute*

```python
WORLD_CAP = 40
```

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

## lawref.fuzz.cap_lines

*function*

```python
def cap_lines(report: dict) -> list[str]
```

Строки о капах — одни на текстовый вид и на потребителей.

Называется цена капа: сколько подстановок срезано и у каких непокрытых
правил цель могла не поместиться в мир. По ним «без применения» читается
как «не искали», а не как «мёртвая норма».

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

## lawref.fuzz.render_text

*function*

```python
def render_text(report: dict) -> str
```

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

## lawref.fuzz.report_bytes

*function*

```python
def report_bytes(report: dict) -> bytes
```

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

## lawref.fuzz.run_fuzz

*function*

```python
def run_fuzz(document: dict, seed: int, worlds: int, world_cap: int = WORLD_CAP, targeted: int = 0, max_groundings: int = MAX_GROUNDINGS) -> dict[str, Any]
```

Прогнать фаззер; отчёт детерминирован кортежем
(документ, сид, миры, кап мира, targeted, кап подстановок).

Оба капа названы в манифесте и, когда режут, — поимённо: предикаты с
усечённым произведением (`groundingsTruncated`) и непокрытые правила, у
которых хоть один релевантный предикат усечён или плотный мир цели не
поместился в кап (`coverage.capBound`). «Без применения» под капом и
«без применения» при полном пространстве — разные ответы, и до 01.09.2026
отчёт их не различал: непокрытое читалось как мёртвое право.

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