# TransformEngine

Normalize formulas with a profile, tune the pipeline, and read the transform report.

https://texform.dev/api/python/transform-engine

## `TransformEngine`

Kind: class

```python
TransformEngine(profile: TransformProfile, knowledge_base: KnowledgeBase | None = None, disable_rules: list[str] | None = None, default_parse_config: ParseConfig | None = None) -> None
```

Normalize a formula into the canonical form selected by a profile.

The engine runs a multi-phase pipeline (LowerAttributes, a fixed-point
Rewrite loop, FinalizeAst, FlattenGroups). A profile picks rule levels;
``TransformConfig`` is nested by phase and controls per-run switches
without changing the selected rule set. The engine also bundles a parser, so
it exposes ``parse`` and shares its immutable ``knowledge_base()``.

Since 0.4.0 the bundled parser defaults to ``ParseConfig`` ``LENIENT``, and
``TransformConfig`` is the nested four-phase object (not flat
``rewrite_enabled`` / ``max_iterations`` keys). Per-call ``config`` must be a
complete ``TransformConfig`` (or ``ParseConfig`` on ``parse``); a dict
passed as ``config`` raises ``ConfigError``. Other keywords are overlays
(``normalize(src, rewrite={"enabled": False})``). Nested overlay values must
be dicts, not phase-config class instances. Construct a full object with
``TransformConfig(...)`` (all four phases required) or the profile
classmethods ``authoring()`` / ``faithful()`` / ``corpus()`` / ``equiv()``.

Normalization is gated on a complete tree: an incomplete parse raises
``ParseError``, since normalizing a tree with holes is meaningless. For the
conceptual model — profiles, the pipeline, and the eliminated-form contract —
see the Transforms guide.

```python
import texform

engine = texform.TransformEngine(profile="corpus")
engine.normalize(r"a \over b")  # '\frac { a } { b }'
engine.normalize(r"a \over b", rewrite={"enabled": False})
engine.normalize(r"a \over b", reject_unknown=True, flatten_groups={"enabled": False})
reported = engine.normalize_with_report(r"a \over b")
reported["normalized"]  # '\frac { a } { b }'
cfg = engine.default_transform_config()
cfg.rewrite.max_iterations = 50
result = engine.parse(r"a \over b")
engine.transform(result["document"], cfg)
engine.transform_with_report(result["document"], texform.TransformConfig.faithful(), rewrite={"enabled": False})
```

- [TransformConfig](https://texform.dev/api/python/transform-engine.md#TransformConfig)
- [NormalizeReportResult](https://texform.dev/api/python/transform-engine.md#NormalizeReportResult)
- [TransformReport](https://texform.dev/api/python/transform-engine.md#TransformReport)
- [Parser](https://texform.dev/api/python/parser.md#Parser)
- [Transforms](https://texform.dev/docs/transforms.md)

#### `TransformEngine`

```python
TransformEngine(profile: TransformProfile, knowledge_base: KnowledgeBase | None = None, disable_rules: list[str] | None = None, default_parse_config: ParseConfig | None = None) -> None
```

Construct an engine sharing knowledge; invalid profiles or rules raise ConfigError.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `profile` | TransformProfile | — |  |
| `knowledge_base` | KnowledgeBase | None | None |  |
| `disable_rules` | list[str] | None | None |  |
| `default_parse_config` | ParseConfig | None | None |  |

#### `normalize`

```python
normalize(src: str, config: TransformConfig | None = None, **overrides) -> str
```

Parse, transform, and serialize a formula in one call.

Normalization is gated on a complete tree. If the input cannot produce a
complete tree, ``normalize`` raises ``ParseError`` carrying the
diagnostics and the partial document. Empty input is complete and
normalizes normally. This path returns the serialized string and does
not build a report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | str | — | The LaTeX source string. |
| `config` | TransformConfig | None | None | A complete ``TransformConfig``; it replaces only the transform half of the baseline. ``**overrides`` are layered on top. A dict here raises ``ConfigError``. |
| `**overrides` | Unpack[NormalizeOverrides] | — | Keyword overlay from ``NormalizeOverrides`` (parse keys plus nested phase dicts). Nested values must be dicts, not config class instances. |

**Returns** `str` The serialized LaTeX string.

- `ParseError`: If the source does not parse into a complete tree.
- `ConfigError`: If ``config`` is not a ``TransformConfig``, a dict is passed as ``config``, or an override key or value is invalid.

```python
engine = texform.TransformEngine(profile="corpus")
engine.normalize(r"\dv{f}{x}")
# '\frac { \mathrm { d } f } { \mathrm { d } x }'
```

- [TransformEngine.normalize_with_report](https://texform.dev/api/python/transform-engine.md#TransformEngine.normalize_with_report)
- [TransformEngine.transform](https://texform.dev/api/python/transform-engine.md#TransformEngine.transform)

#### `normalize_with_report`

```python
normalize_with_report(src: str, config: TransformConfig | None = None, **overrides) -> NormalizeReportResult
```

Parse, transform, and serialize a formula, returning text and a report.

Accepts the same source, ``config``, and keyword overlays as
``normalize``. Output text and errors follow that contract. The report
is diagnostic: its fields, phase divisions, and counters are not part
of the stable compatibility promise. A failure does not return a
partial report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | str | — | The LaTeX source string. |
| `config` | TransformConfig | None | None | A complete ``TransformConfig``, with the same meaning as on ``normalize``. |
| `**overrides` | Unpack[NormalizeOverrides] | — | Keyword overlay from ``NormalizeOverrides``. |

**Returns** `NormalizeReportResult` A ``NormalizeReportResult`` dict with ``normalized`` and ``report``.

- `ParseError`: If the source does not parse into a complete tree.
- `ConfigError`: If ``config`` or an override is invalid.

- [TransformEngine.normalize](https://texform.dev/api/python/transform-engine.md#TransformEngine.normalize)
- [TransformReport](https://texform.dev/api/python/transform-engine.md#TransformReport)

#### `transform`

```python
transform(document: Document, config: TransformConfig | None = None, **overrides) -> None
```

Transform a live ``Document`` in place.

``transform`` accepts documents sharing this engine's knowledge-base
instance, including constructed, copied, and imported snapshots.
The document must also be complete;
a document that ``has_errors()`` is rejected with ``TransformError``.
This path returns ``None`` and does not build a report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `document` | Document | — | The live ``Document`` to update in place. |
| `config` | TransformConfig | None | None | A complete ``TransformConfig``; ``**overrides`` are layered on top. It does not accept parse options. A dict here raises ``ConfigError``. |
| `**overrides` | Unpack[TransformOverrides] | — | Keyword overlay from ``TransformOverrides``. Nested values must be dicts, not config class instances. |

**Returns** `None` ``None``.

- `TransformError`: If the document has a different knowledge base, has parse errors, or on a contract violation.
- `ConfigError`: If ``config`` is not a ``TransformConfig``, a dict is passed as ``config``, or an override key or value is invalid.

```python
engine = texform.TransformEngine(profile="corpus")
result = engine.parse(r"a \over b")
document = result["document"]
assert document is not None
engine.transform(document)
document.to_latex()  # '\frac { a } { b }'
```

- [TransformEngine.transform_with_report](https://texform.dev/api/python/transform-engine.md#TransformEngine.transform_with_report)
- [TransformEngine.normalize](https://texform.dev/api/python/transform-engine.md#TransformEngine.normalize)

#### `transform_with_report`

```python
transform_with_report(document: Document, config: TransformConfig | None = None, **overrides) -> TransformReport
```

Transform a live ``Document`` in place and return its diagnostic report.

Accepts the same document, ``config``, and keyword overlays as
``transform``. Document ownership, completeness, and errors follow that
contract. The report is diagnostic and is not part of the stable
compatibility promise. A failure does not return a partial report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `document` | Document | — | The live ``Document`` to update in place. |
| `config` | TransformConfig | None | None | A complete ``TransformConfig``, with the same meaning as on ``transform``. |
| `**overrides` | Unpack[TransformOverrides] | — | Keyword overlay from ``TransformOverrides``. |

**Returns** `TransformReport` The diagnostic transform report dict.

- `TransformError`: If the document has a different knowledge base, has parse errors, or on a contract violation.
- `ConfigError`: If ``config`` or an override is invalid.

- [TransformEngine.transform](https://texform.dev/api/python/transform-engine.md#TransformEngine.transform)
- [TransformReport](https://texform.dev/api/python/transform-engine.md#TransformReport)

#### `parse`

```python
parse(src: str, config: ParseConfig | None = None, **overrides) -> ParseResult
```

Parse a LaTeX string using the engine's bundled parser.

Uses this engine's parser and default parse config. Engines default to
lenient parsing; pass ``config`` to override it per call. A document
produced here is owned by this engine and is the only kind ``transform``
accepts.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | str | — | The LaTeX source string. |
| `config` | ParseConfig | None | None | A complete ``ParseConfig``; ``**overrides`` are layered on top. ``None`` uses the engine default. A dict here raises ``ConfigError``. |
| `**overrides` | Unpack[ParseOverrides] | — | Keyword overlay from ``ParseOverrides``. |

**Returns** `ParseResult` A ``ParseResult`` dict with ``document`` and ``diagnostics``.

- `ConfigError`: If ``config`` is not a ``ParseConfig``, a dict is passed as ``config``, or an override key or value is invalid.

- [Parser.parse](https://texform.dev/api/python/parser.md#Parser.parse)
- [TransformEngine.transform](https://texform.dev/api/python/transform-engine.md#TransformEngine.transform)

#### `default_parse_config`

```python
default_parse_config() -> ParseConfig
```

Return a new ``ParseConfig`` holding this engine's parse defaults.

**Returns** `ParseConfig`

#### `default_transform_config`

```python
default_transform_config() -> TransformConfig
```

Return a new ``TransformConfig`` holding this engine's transform defaults.

**Returns** `TransformConfig`

### Knowledge-base lookups

Query the knowledge the parser loaded. Predicate methods take a single `name`; lookup methods take `name` and a `mode` of `"math"` or `"text"` and return a knowledge-entry dict or `None`.

#### `knowledge_base`

```python
knowledge_base() -> KnowledgeBase
```

Return the immutable knowledge base shared with parsed documents.

**Returns** `KnowledgeBase`

## `TransformConfig`

Kind: class

```python
TransformConfig(lower_attributes: LowerAttributesConfig, rewrite: RewriteConfig, finalize_ast: FinalizeAstConfig, flatten_groups: FlattenGroupsConfig) -> None
```

Complete transform configuration, nested by pipeline phase.

Since 0.4.0 this is the only accepted ``config=`` type for ``transform`` /
``normalize``. A dict passed as ``config`` raises ``ConfigError``; use
keyword overlays (``normalize(src, rewrite={"enabled": False})``) or
construct this class. The constructor requires all four phase configs; the
classmethods ``authoring()`` / ``faithful()`` / ``corpus()`` / ``equiv()``
return the defaults a profile actually uses.

The four attributes are shared references: ``cfg.rewrite.enabled = False``
is visible through ``cfg.rewrite.enabled`` and takes effect when the object
is passed as ``config``. Nested overlay values must be dicts, not these
phase-config instances.

```python
config = texform.TransformConfig(
    lower_attributes=texform.LowerAttributesConfig(),
    rewrite=texform.RewriteConfig(max_iterations=50),
    finalize_ast=texform.FinalizeAstConfig(),
    flatten_groups=texform.FlattenGroupsConfig(enabled=False),
)
config.rewrite.max_iterations  # 50
texform.TransformConfig.corpus().flatten_groups.preserve_rendered_spacing  # False
```

- [TransformEngine](https://texform.dev/api/python/transform-engine.md#TransformEngine)
- [RewriteConfig](https://texform.dev/api/python/transform-engine.md#RewriteConfig)
- [LowerAttributesConfig](https://texform.dev/api/python/transform-engine.md#LowerAttributesConfig)
- [FinalizeAstConfig](https://texform.dev/api/python/transform-engine.md#FinalizeAstConfig)
- [FlattenGroupsConfig](https://texform.dev/api/python/transform-engine.md#FlattenGroupsConfig)

#### `lower_attributes`

The LowerAttributes phase config (shared reference).

#### `rewrite`

The Rewrite phase config (shared reference).

#### `finalize_ast`

The FinalizeAst phase config (shared reference).

#### `flatten_groups`

The FlattenGroups phase config (shared reference).

#### `TransformConfig`

```python
TransformConfig(lower_attributes: LowerAttributesConfig, rewrite: RewriteConfig, finalize_ast: FinalizeAstConfig, flatten_groups: FlattenGroupsConfig) -> None
```

Construct a transform configuration. All four phases are required.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `lower_attributes` | LowerAttributesConfig | — | The LowerAttributes phase config. |
| `rewrite` | RewriteConfig | — | The Rewrite phase config. |
| `finalize_ast` | FinalizeAstConfig | — | The FinalizeAst phase config. |
| `flatten_groups` | FlattenGroupsConfig | — | The FlattenGroups phase config. |

- `TypeError`: If a required phase argument is missing. Start with a profile classmethod such as ``TransformConfig.corpus()`` to change only selected fields.

#### `authoring`

```python
authoring() -> TransformConfig
```

Return the transform config the ``authoring`` profile uses by default.

**Returns** `TransformConfig`

#### `faithful`

```python
faithful() -> TransformConfig
```

Return the transform config the ``faithful`` profile uses by default.

**Returns** `TransformConfig`

#### `corpus`

```python
corpus() -> TransformConfig
```

Return the transform config the ``corpus`` profile uses by default.

**Returns** `TransformConfig`

#### `equiv`

```python
equiv() -> TransformConfig
```

Return the transform config the ``equiv`` profile uses by default.

**Returns** `TransformConfig`

## `RewriteConfig`

Kind: class

```python
RewriteConfig(enabled: bool = True, max_iterations: int = 100) -> None
```

Complete Rewrite phase configuration.

Nested under ``TransformConfig.rewrite``. Disabling this phase leaves
legacy syntax such as ``\over`` untouched; it does not change which rule
levels the profile selected. Overlay with ``rewrite={"enabled": False}``;
do not pass this class as a nested overlay value.

```python
cfg = texform.RewriteConfig(max_iterations=50)
cfg.enabled  # True
cfg.max_iterations  # 50
```

#### `enabled`

Whether the phase runs. Defaults to ``True``.

#### `max_iterations`

The cap on fixed-point passes. Defaults to ``100``.

#### `RewriteConfig`

```python
RewriteConfig(enabled: bool = True, max_iterations: int = 100) -> None
```

Construct a Rewrite phase configuration.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | bool | True | Whether the phase runs. |
| `max_iterations` | int | 100 | The cap on fixed-point passes. |

## `LowerAttributesConfig`

Kind: class

```python
LowerAttributesConfig(enabled: bool = True) -> None
```

Complete LowerAttributes phase configuration.

This is a nested field of ``TransformConfig``, not a dict overlay. Pass the
parent ``TransformConfig`` as ``config``; to overlay only this phase use
``lower_attributes={"enabled": False}``. A dict passed as ``config`` on
``transform`` / ``normalize`` raises ``ConfigError``.

```python
texform.LowerAttributesConfig().enabled  # True
texform.LowerAttributesConfig(enabled=False).enabled  # False
```

#### `enabled`

Whether the phase runs. Defaults to ``True``.

#### `LowerAttributesConfig`

```python
LowerAttributesConfig(enabled: bool = True) -> None
```

Construct a LowerAttributes phase configuration.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | bool | True | Whether the phase runs. |

## `FinalizeAstConfig`

Kind: class

```python
FinalizeAstConfig(enabled: bool = True) -> None
```

Complete FinalizeAst phase configuration.

Nested under ``TransformConfig.finalize_ast``. The phase performs local AST
cleanup such as merging adjacent ``Prime`` nodes and normalizing text
sequences. Overlay with ``finalize_ast={"enabled": False}``.

```python
texform.FinalizeAstConfig().enabled  # True
```

#### `enabled`

Whether the phase runs. Defaults to ``True``.

#### `FinalizeAstConfig`

```python
FinalizeAstConfig(enabled: bool = True) -> None
```

Construct a FinalizeAst phase configuration.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | bool | True | Whether the phase runs. |

## `FlattenGroupsConfig`

Kind: class

```python
FlattenGroupsConfig(enabled: bool = True, preserve_rendered_spacing: bool = True) -> None
```

Complete FlattenGroups phase configuration.

Nested under ``TransformConfig.flatten_groups``. ``enabled`` governs whether
the phase runs. ``preserve_rendered_spacing`` keeps groups whose only
public-facing effect is rendered math spacing; it does not control
serializer source whitespace (see ``SerializeOptions``). Structural guards
stay on even when ``preserve_rendered_spacing`` is ``False``. Constructor
defaults match the authoring / faithful strict pair (both ``True``); the
``corpus`` and ``equiv`` profiles leave ``preserve_rendered_spacing`` off.
Overlay with ``flatten_groups={"enabled": False}``; a dict passed as
``config`` still raises ``ConfigError``.

```python
texform.FlattenGroupsConfig().enabled  # True
texform.FlattenGroupsConfig().preserve_rendered_spacing  # True
texform.FlattenGroupsConfig(enabled=False).enabled  # False
texform.TransformConfig.corpus().flatten_groups.preserve_rendered_spacing  # False
```

#### `enabled`

Whether the phase runs. Defaults to ``True``.

#### `preserve_rendered_spacing`

Keep groups whose only public-facing effect is rendered math spacing. Defaults to ``True``. This is not serializer source spacing.

#### `FlattenGroupsConfig`

```python
FlattenGroupsConfig(enabled: bool = True, preserve_rendered_spacing: bool = True) -> None
```

Construct a FlattenGroups phase configuration.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `enabled` | bool | True | Whether the phase runs. |
| `preserve_rendered_spacing` | bool | True | Keep groups whose only public-facing effect is rendered math spacing. |

## `NormalizeOverrides`

Kind: class

Extends: ParseOverrides, TransformOverrides

Flat parse+transform overlays for ``normalize``.

Combines ``ParseOverrides`` keys with nested phase overlays from
``TransformOverrides``. A dict passed as ``config`` still raises
``ConfigError``; these keys are keywords only
(``normalize(src, rewrite={"enabled": False}, reject_unknown=True)``).

```python
engine = texform.TransformEngine(profile="corpus")
engine.normalize(r"a \over b", reject_unknown=True)
# '\frac { a } { b }'
```

## `TransformOverrides`

Kind: typedDict

Keyword overlays for ``transform``.

Each nested value must be a dict of that phase's overlay keys, not a
complete phase-config class instance.

| Name | Type | Description |
| --- | --- | --- |
| `lower_attributes` | LowerAttributesOverrides | Overlay dict for the LowerAttributes phase. |
| `rewrite` | RewriteOverrides | Overlay dict for the Rewrite phase. |
| `finalize_ast` | FinalizeAstOverrides | Overlay dict for the FinalizeAst phase. |
| `flatten_groups` | FlattenGroupsOverrides | None | Overlay dict for the FlattenGroups phase. |

## `RewriteOverrides`

Kind: typedDict

Keyword overlays for the Rewrite phase.

Nested under ``transform`` / ``normalize`` as ``rewrite={...}``. The nested
value must be a dict, not a ``RewriteConfig`` instance.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | bool | Overlay for ``RewriteConfig.enabled``. |
| `max_iterations` | int | Overlay for ``RewriteConfig.max_iterations``. |

## `LowerAttributesOverrides`

Kind: typedDict

Keyword overlays for the LowerAttributes phase.

Nested under ``transform`` / ``normalize`` as ``lower_attributes={...}``.
The nested value must be a dict, not a ``LowerAttributesConfig`` instance.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | bool | Overlay for ``LowerAttributesConfig.enabled``. |

## `FinalizeAstOverrides`

Kind: typedDict

Keyword overlays for the FinalizeAst phase.

Nested under ``transform`` / ``normalize`` as ``finalize_ast={...}``. The
nested value must be a dict, not a ``FinalizeAstConfig`` instance.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | bool | Overlay for ``FinalizeAstConfig.enabled``. |

## `FlattenGroupsOverrides`

Kind: typedDict

Keyword overlays for the FlattenGroups phase.

Nested under ``transform`` / ``normalize`` as ``flatten_groups={...}``. The
nested value must be a dict, not a ``FlattenGroupsConfig`` instance.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | bool | None | Overlay for ``FlattenGroupsConfig.enabled``. ``None`` leaves the current value unchanged. |
| `preserve_rendered_spacing` | bool | None | Overlay for ``FlattenGroupsConfig.preserve_rendered_spacing``. ``None`` leaves the current value unchanged. |

## `NormalizeReportResult`

Kind: typedDict

Text plus the diagnostic report from one explicit normalize report call.

Plain ``normalize`` returns the string directly and does not build this
object.

| Name | Type | Description |
| --- | --- | --- |
| `normalized` | str | The serialized LaTeX string. |
| `report` | TransformReport | The diagnostic transform report for this call. |

- [TransformReport](https://texform.dev/api/python/transform-engine.md#TransformReport)

## `TransformReport`

Kind: typedDict

Diagnostic report for one explicit report call.

Output text and errors follow the ordinary transform contract. Report
fields, phase divisions, and these counters are diagnostic: they are not
part of the stable compatibility promise. A disabled phase stays present as
zeros or an empty list. The Python report uses snake_case; JavaScript
exposes the same data in camelCase.

| Name | Type | Description |
| --- | --- | --- |
| `warnings` | list[TransformWarning] | Unknown input names, deduplicated and sorted by kind and name. |
| `lower_attributes` | LowerAttributesReport | LowerAttributes activity, summed across its two passes. |
| `rewrite` | RewriteReport | Rewrite iterations and per-rule outcomes. |
| `finalize_ast` | FinalizeAstReport | Prime merges and text normalizations. |
| `flatten_groups` | FlattenGroupsReport | Flatten actions and guard hits. |

- [NormalizeReportResult](https://texform.dev/api/python/transform-engine.md#NormalizeReportResult)
- [TransformEngine](https://texform.dev/api/python/transform-engine.md#TransformEngine)

## `TransformWarning`

Kind: typedDict

An unknown input name whose arguments or scope cannot be guaranteed.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['unknown-command', 'unknown-environment'] |  |
| `name` | str |  |
| `message` | str |  |

## `LowerAttributesReport`

Kind: typedDict

The LowerAttributes phase report.

| Name | Type | Description |
| --- | --- | --- |
| `attributes` | list[AttributeStat] | Per-attribute activity, sorted by ``attr`` then ``value``. |
| `eliminated_empty_segments` | int | Empty attribute segments removed by the phase. |

## `AttributeStat`

Kind: typedDict

Activity for one ``(attr, value)`` pair in LowerAttributes.

| Name | Type | Description |
| --- | --- | --- |
| `attr` | str | Stable attribute name, such as ``"math_font"`` or ``"text_size"``. |
| `value` | str | Stable value token for that attribute. |
| `consumed` | AttributeFormCounts | Input forms consumed by the phase. |
| `redundant` | AttributeFormCounts | Consumed forms that did not change the emitted attribute state. |
| `emitted` | AttributeFormCounts | Canonical forms emitted by the phase. |

## `AttributeFormCounts`

Kind: typedDict

Counts of one attribute form, split by carrier.

| Name | Type | Description |
| --- | --- | --- |
| `declaratives` | int | Count carried by declarative markup such as ``{\bf ...}``. |
| `prefixes` | int | Count carried by prefix commands such as ``\mathbf{...}``. |

## `RewriteReport`

Kind: typedDict

The Rewrite phase report.

| Name | Type | Description |
| --- | --- | --- |
| `iterations` | int | Fixed-point passes, including the final unchanged convergence check. Zero when the phase is disabled or no rules are scheduled. |
| `rules` | list[RewriteRuleStat] | Rules that recorded activity, sorted by ``key``. |

## `RewriteRuleStat`

Kind: typedDict

One rewrite rule's outcome for a single call.

| Name | Type | Description |
| --- | --- | --- |
| `key` | str | Stable rule key. |
| `applied_count` | int | Times the rule applied. |
| `skipped_count` | int | Times the scheduler matched the rule and ``apply`` returned skipped. |

## `FinalizeAstReport`

Kind: typedDict

The FinalizeAst phase report.

| Name | Type | Description |
| --- | --- | --- |
| `prime_run_merges` | int | Contiguous ``Prime`` runs merged. Each run counts once. |
| `text_normalizations` | int | Text segments or text argument slots whose content changed. |

## `FlattenGroupsReport`

Kind: typedDict

The FlattenGroups phase report.

| Name | Type | Description |
| --- | --- | --- |
| `actions` | FlattenGroupsActionCounts | Flatten actions that changed the tree. |
| `guard_hits` | FlattenGroupsGuardCounts | Preserve-guard hits for this call. |

## `FlattenGroupsActionCounts`

Kind: typedDict

Flatten actions that changed the tree.

| Name | Type | Description |
| --- | --- | --- |
| `removed_empty` | int | Empty groups removed. |
| `replaced_single_child` | int | Groups replaced by their only child. |
| `inlined_multi_child` | int | Multi-child groups inlined into the parent. |
| `unwrapped_slot` | int | Slot wrappers removed. |

## `FlattenGroupsGuardCounts`

Kind: typedDict

Preserve-guard hits for one FlattenGroups run.

A hit is the first guard branch reached for a group, plus the scripted-base
sub-count. ``command_contact_via_scripted_base`` is also included in
``command_contact``. These counters are not a partition of preserved groups.

| Name | Type | Description |
| --- | --- | --- |
| `unknown_command_arguments` | int | Possible arguments following an unknown command. |
| `argument_capture` | int | Groups whose removal would let a command before or inside them read the next token as an omitted optional or delimited argument. |
| `declarative_scope` | int | Declarative-scope protection. |
| `script_base` | int | Script-base protection. |
| `env_body` | int | Environment-body protection. |
| `infix_scope` | int | Infix-scope protection. |
| `command_contact` | int | Command-contact protection. |
| `command_contact_via_scripted_base` | int | Command contact established through a scripted base. |
| `empty_group` | int | Empty-group protection. |
| `lone_atom_spacing_char` | int | Single spacing-character protection. |
| `leading_atom_spacing_char` | int | Leading spacing-character protection. |
| `delimited_pair` | int | Delimited-pair protection. |

## `TransformProfile`

Kind: typeAlias

```python
Literal['authoring', 'faithful', 'corpus', 'equiv']
```

Normalization profile name: ``"authoring"``, ``"faithful"``, ``"corpus"``, or ``"equiv"``.

