For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /packs/languages/python/state.md.
Quick start

State

Keep domain values immutable through their complete object graph.

Ownership

Why

A frozen dataclass containing a mutable list still allows another caller to change that list.

Rules

  • MUST use tuples, frozensets, or validated immutable records for retained domain collections. [review]
  • MUST use immutable fields inside frozen records. [review]
  • MUST return a new value for domain state transitions. [review]
  • MUST avoid mutating input lists, dictionaries, or caller-owned objects. [review]
  • MUST keep application state out of module globals and captured mutable closures. [review]
  • MUST avoid reassigning existing domain bindings; use Final where the checker can establish the rule. [review]
  • MUST keep mutable external handles in resource adapters. [review]
  • MAY use declarative frozen dataclasses to define data rather than mutable application services. [review]

Example

from dataclasses import dataclass, replace


@dataclass(frozen=True)
class Selection:
    names: tuple[str, ...]


def append_name(*, selection: Selection, name: str) -> Selection:
    return replace(selection, names=(*selection.names, name))


original = Selection(("docs",))
updated = append_name(selection=original, name="code")
assert original.names == ("docs",)
assert updated.names == ("docs", "code")

[review]

Frozen data definitions and configured typing cover some mutation paths. Tests and review check nested fields, aliases, and state transitions.

Enforcement

Frozen data definitions and configured typing cover some mutation paths. Tests and review check nested fields, aliases, and state transitions.