| name | python-values-success |
| description | Build the five proven shapes for domain data — semantic scalar, value object, concept model, collection, union. Fires before writing a bare primitive field, a dataclass/NamedTuple/TypedDict, a list/set/dict field, a T | None field, a raw Literal or bare StrEnum field, or a match/if-elif/isinstance ladder selecting by kind. |
Values
The data-shape constructs: what a domain fact is, proven by construction. One axis per pattern — scalar (one value), value object (a few values, no identity), concept model (a full thing), collection (a proven sequence or namespace), union (a choice among structures).
Semantic Scalar
Definition
A frozen RootModel[P] over one primitive or one closed value space, carrying a Field(...) constraint or a docstring stating why the open range is the domain fact. The atomic domain value: it references no domain type.
Required Form
class Price(RootModel[Decimal], frozen=True):
root: Decimal = Field(gt=0, decimal_places=8)
class Quantity(RootModel[Decimal], frozen=True):
root: Decimal = Field(gt=0)
class OrderId(RootModel[str], frozen=True):
root: str = Field(min_length=1)
class Side(StrEnum):
BUY = "buy"
SELL = "sell"
class OrderSide(RootModel[Side], frozen=True):
root: Side
@property
def opposite(self) -> "OrderSide":
return OrderSide({Side.BUY: Side.SELL, Side.SELL: Side.BUY}[self.root])
class OrderNote(RootModel[str], frozen=True):
"""A trader's free-text note on an order. Unconstrained on purpose: any text, including empty, is a legal note."""
root: str
The allowed primitives are str, int, float, Decimal, bool, bytes, and date. A closed vocabulary wraps a StrEnum or Literal value space; the StrEnum is the value space, the role gt=0 plays. A scalar derivation on a closed value space selects by data lookup, never by a ternary or a branch.
Sorting Rules
One axis, every member the same kind of thing: a scalar. A member needing a field or behavior a sibling lacks: two axes, a union. A value composed of other values: a value object or concept model.
Replaced Forms
A bare primitive standing for a domain value holds its meaning in a variable name no downstream reader receives. A vocabulary scattered as string literals is unnamed and unproven. An unconstrained RootModel[str] with no docstring and no genuine name is a structure with no meaning.
Construct-Specific Doctrine
A scalar constructs where its composite is proven: a raw value passed where the scalar field stands constructs it inside the composite's own call. Pass the declared value onward. .root is read in exactly two settings: inside a derivation's one returned expression, where the bare value immediately feeds the construction of the declared type the derivation returns, and where the program meets the wire, at a client binding or a route reply. A bare .root value is consumed by the construction or the client call that reads it, never assigned, stored, or passed onward.
Allowed Patterns
class X(RootModel[P], frozen=True) over one allowed primitive with a Field(...) constraint stating the domain's bound
class X(RootModel[E], frozen=True) over a StrEnum or Literal value space
- an unconstrained scalar whose docstring states why the open range is the domain fact
- a derivation on the scalar returning a declared type, selecting by data lookup on a closed space
Forbidden
- a bare primitive used as a domain value
- string literals used as a closed vocabulary
- a standalone enum used as a field type
- an unconstrained
RootModel without a stated openness
- a ternary or branch inside a scalar derivation
- a bare
.root value assigned, stored, or passed onward; .root is read only inside a derivation's returned construction, at a client binding, or at a route reply
Halt Rule
Halt when a member of the value space needs a field or behavior a sibling lacks, or when a value has neither a statable constraint nor a statable openness. Report the row and the member or bound: the meaning is a union or is not yet understood, and the table is not finished.
Value Object
Definition
A frozen BaseModel composing scalars into a small value with no identity, equal by value: a measurement, a description, an amount. The composition layer between the semantic scalar and the concept model.
Required Form
class Spread(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
best_bid: Price
width: SpreadWidth
@cached_property
def best_ask(self) -> Price:
return Price(self.best_bid.root + self.width.root)
Sorting Rules
A single value is a semantic scalar. A full domain thing or fact, anything with domain identity or a kind pin, is a concept model. A value object never holds a client, never pins a kind, and two value objects with equal fields are the same value.
Replaced Forms
A tuple or dict of primitives carries the parts without the proof or the name. A dataclass pair carries the shape without construction as proof. A validator asserting a relation between fields is a check performed inside construction; the relation is reparameterized instead.
Construct-Specific Doctrine
A relation no single field constrains is part of the composite proof, never a guard after it: reparameterize so the relation collapses into a single-field constraint and a derivation. Spread holds best_bid and a non-negative width and derives best_ask, so an inverted spread has no representation. A reparameterization that seems to distort the model is the signal that the related fields are their own concept, not yet factored.
Allowed Patterns
class X(BaseModel) with model_config = ConfigDict(frozen=True, extra="forbid"), fields scalars or value objects
- a cross-field relation reparameterized into one constrained field plus a derivation
- derivations implying the value's facts
Forbidden
- a bare primitive field
- a
T | None field
- a kind pin or any identity field
- a client or handle as a field
- a validator asserting a relation between fields
- a stored field derivable from the others
Halt Rule
Halt when the value needs identity, a kind, or a field that is itself a full domain concept, or when a relation resists reparameterization. Report the row and the field or relation: the meaning is a concept model or an unfactored concept, and the table is not finished.
Concept Model
Definition
A frozen BaseModel composing declared types into one full domain thing or domain fact. The product type whose sum-type sibling is the union: the type is the concept, each field a relation to another concept.
Required Form
class Fill(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
order_id: OrderId
account_id: AccountId
fill_price: Price
filled_quantity: Quantity
class Position(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[PositionKind.OPEN] = PositionKind.OPEN
prior: PositionState
fill: Fill
@cached_property
def exposure(self) -> Exposure:
return Exposure(self.prior.exposure.root + self.fill.exposure.root)
Every field is a declared type: never a bare primitive, never T | None, and never a value derivable from other fields. A concept model that pins a kind is a union variant.
Sorting Rules
A small identity-less composition of scalars, equal by value, is a value object. A single value is a semantic scalar. A choice among concept models is a union, and a concept model pinning one axis member is that union's variant. Another system's shape is a foreign model; this program's API shape is a contract model; mutable state is the consistency model.
Replaced Forms
A dataclass, NamedTuple, TypedDict, or dict-shaped value carries the shape without the proof. A validator that asserts a relation is a check performed inside construction; the relation reparameterizes. A base class created only to share fields is a second structure for one meaning; the shared field is already shared as the leaf both models compose.
Construct-Specific Doctrine
Construction discipline. A composite constructs whole in one call: constituents are proven by coercion inside it, never pre-constructed one at a time beside it. Keywords express the lift from a foreign result's attributes; from_attributes lifts a whole object; model_validate_json lifts serialized data. A dict assembled by hand and fed to model_validate where keywords express it is a mapper in miniature. A coalesce on the way in (x or default) manufactures a value nothing proved. A check after construction un-proves the value it guards.
Absence. "May be missing" is never a field. Absence that means something is a union variant named for what absence means, or separate models when absence changes the state shape. When constructing from foreign data, an omitted key resolves to a default that states what omission means, or a variant when omission means a different fact; bare None never crosses into the domain.
class PositionKind(StrEnum):
OPEN = "open"
FLAT = "flat"
class Flat(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[PositionKind.FLAT] = PositionKind.FLAT
@property
def exposure(self) -> Exposure:
return Exposure(Decimal("0"))
class QuoteSubscription(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
product: ProductId
depth: BookDepth = BookDepth(50)
Flat is the account with no position, and it carries no position fields: absence changed the state shape, so absence is its own variant. QuoteSubscription.depth defaults to the venue default, so an omitted foreign key never enters as None.
Allowed Patterns
class X(BaseModel) with model_config = ConfigDict(frozen=True, extra="forbid")
- every field a declared type: a scalar, a value object, a collection element form, a concept model, or a union
from_attributes=True in the config when the model lifts from objects
- a defaulted field whose default states what omission means
- derivations implying the model's facts
- the kind pin
kind: Literal[Axis.MEMBER] = Axis.MEMBER when the row declares a variant
Forbidden
- a bare primitive field
- a
T | None field
- a stored field derivable from the others
- a validator that computes, normalizes, or asserts
- a
Present or Absent wrapper
- subclassing a domain model for field reuse
- a constituent constructed in a separate statement beside its composite
- an unfrozen model that is not the consistency model
Halt Rule
Halt when a field has no declared row, when a cross-field relation will not reparameterize into a constraint plus a derivation, or when an absence has no statable meaning. Report the row and the field or relation: the meaning is not yet modeled, and the table is not finished.
Collection
Definition
A frozen RootModel[tuple[T, ...]] whose element T is a declared type, for a sequence that is itself a domain thing with its own name, constraint, or derivation; or a frozen RootModel[dict[K, V]] over a declared key K and value V, for a namespace whose key-uniqueness is the domain fact. A sequence with no meaning of its own is a tuple[T, ...] field on a model, not a collection.
Required Form
class FillList(RootModel[tuple[Fill, ...]], frozen=True):
root: tuple[Fill, ...] = Field(min_length=1)
fills = FillList(tuple(Fill.model_validate(report) for report in venue_reports))
The collection constructs whole, one expression producing the tuple the RootModel proves.
Sorting Rules
An element that is a bare primitive is an undeclared semantic scalar: build the scalar first. A sequence with no name, constraint, or derivation of its own is a plain tuple[T, ...] field on a value object or concept model. A fact the sequence implies as a whole is a derivation on the named collection.
Replaced Forms
A list, set, or dict field is an unconstrained mutable container where a proven sequence belongs. A loop appending into a container is construction performed as procedure; the comprehension inside the construction call is the whole build.
Construct-Specific Doctrine
A namespace keyed by a domain value, where key-uniqueness is the domain fact, is a keyed collection: a frozen RootModel[dict[K, V]] whose key K is a declared scalar and value V a declared type, paired with a frozen query model holding the collection and a key, whose derivation returns a found-or-missing union. The dict holds one slot per key, so a duplicate key has no representation, and the query model carries the miss, so a dict[key] KeyError or a .get None never appears. This is the named keyed form, never a bare dict field. Any semantic scalar used as the key must define canonical string rendering (__str__ returning its root), proven by a substrate round-trip, because a JSON object key is a string and an unrendered scalar key corrupts on reload. When keys repeat or order is the fact, the sequence form holds instead: an entry model with declared key and value fields, a collection of those entries, and the same query model. A repeated-key question is another query model with a derivation.
class PriceBook(RootModel[dict[ProductId, Price]], frozen=True):
root: dict[ProductId, Price]
class PriceQuery(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
book: PriceBook
product: ProductId
@cached_property
def answer(self) -> PriceFound | PriceMissing:
return next(
(PriceFound(price=price) for key, price in self.book.root.items() if key == self.product),
PriceMissing(product=self.product),
)
Allowed Patterns
field: tuple[T, ...] on a value object or concept model, T a declared type
class Xs(RootModel[tuple[T, ...]], frozen=True) with a Field(...) constraint when the sequence carries its own bound
class Xs(RootModel[dict[K, V]], frozen=True) over a declared key and value when key-uniqueness is the domain fact, paired with a query model returning a found-or-missing union
- a key scalar defining canonical string rendering (
__str__ returning its root), proven to round-trip
- derivations on the named collection returning declared types
- the collection constructed whole in one expression
- a keyed collection, or an entry model with a collection of entries, plus a query model as the shape of any association
Forbidden
- a bare
list, set, or dict field on a domain model
- a collection element typed as a bare primitive
- a loop appending domain values into a collection
KeyError or a default value as domain miss behavior
- a keyed-collection key scalar without canonical string rendering, which corrupts on round-trip
Halt Rule
Halt when the element is not a declared row, or when a cross-element rule cannot be expressed as a constraint or a query model's derivation. Report the row and the rule: the element or the question is not yet modeled, and the table is not finished.
Union
Definition
A closed set of two or more frozen variants over one domain axis, the axis a StrEnum, each variant pinning exactly one member with a defaulted kind: Literal[Axis.MEMBER] field. The structural form of a choice: a decision with consequences is a union of result variants, and identity-carrying data constructs it through the discriminator on its alias.
Required Form
class OrderOutcomeKind(StrEnum):
FILLED = "filled"
REJECTED = "rejected"
class Filled(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[OrderOutcomeKind.FILLED] = OrderOutcomeKind.FILLED
fill_price: Price
filled_quantity: Quantity
@property
def headline(self) -> Headline:
return Headline("order filled")
class Rejected(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[OrderOutcomeKind.REJECTED] = OrderOutcomeKind.REJECTED
reason: RejectionReason
@property
def headline(self) -> Headline:
return Headline("order rejected")
OrderOutcome = Annotated[Filled | Rejected, Field(discriminator="kind")]
The defaulted pin puts the identity in every serialization of the value. A fact that differs by variant is each variant's own same-named derivation, read from the union value: a consumer reads outcome.headline, and the static checker requires every variant to define headline.
Variants with identical payloads differ in nothing but identity, so identity is a field or it is nowhere:
class HaltKind(StrEnum):
HALTED = "halted"
RESUMED = "resumed"
class Halted(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[HaltKind.HALTED] = HaltKind.HALTED
at: Timestamp
class Resumed(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[HaltKind.RESUMED] = HaltKind.RESUMED
at: Timestamp
A yes-or-no decision with consequences is a two-variant union, never bool, because each outcome carries its own facts:
class ReviewKind(StrEnum):
APPROVED = "approved"
REFUSED = "refused"
class Approved(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[ReviewKind.APPROVED] = ReviewKind.APPROVED
terms: ApprovalTerms
class Refused(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
kind: Literal[ReviewKind.REFUSED] = ReviewKind.REFUSED
reason: RefusalReason
Sorting Rules
A uniform one-axis vocabulary, every member the same kind of thing, is a semantic scalar over a StrEnum; the moment a member needs a field or behavior a sibling lacks, it is this construct. Foreign data that carries no identity and is expected to fail constructs through the ordered union, never by discriminator. A single variant on its own is a concept model pinning a kind.
Replaced Forms
A match, if/elif chain, or isinstance ladder over variants is selection re-implemented after construction already selected; what differs by variant is the variant's derivation. A bool decision fuses both outcomes and drops both payloads. A raw-string kind or an unpinned kind: Axis admits every member on every variant and identifies nothing. A RootModel wrapped around a union is a class created only to provide model_validate the alias already provides.
Construct-Specific Doctrine
The alias. The discriminator is declared on the union's own alias: Annotated[A | B, Field(discriminator="kind")], one alias, one name, everywhere. In the graph the annotation is inert and the checker narrows through it. Where identity-carrying raw data constructs the union, the alias is the constructor: as a field on a foreign or contract model, or through one module-level TypeAdapter named for the alias when the data arrives with no surrounding modeled structure. Discriminated construction fails on the claimed variant's own fields, never across all variants.
OrderOutcomeConstructor = TypeAdapter(OrderOutcome)
outcome = OrderOutcomeConstructor.validate_json(transport_bytes)
Probes. Before building on a union, construct one variant and read the pin back:
filled = Filled(fill_price=Price("101.50"), filled_quantity=Quantity("3"))
filled.kind is OrderOutcomeKind.FILLED, and kind appears in the serialized data. Before building on the alias, serialize a constructed variant and re-prove it: OrderOutcomeConstructor.validate_json(filled.model_dump_json()) returns a Filled, because the identity was carried in the data. Never author a dict input object as a probe.
Allowed Patterns
- one
StrEnum axis declared beside the variants
- two or more frozen variants, each pinning exactly one member with
kind: Literal[Axis.MEMBER] = Axis.MEMBER
- the alias
Annotated[A | B, Field(discriminator="kind")] as the union's one rendered form
- the alias as a field's type, a derivation's return, or a verb parameter
- a same-named derivation on every variant for any fact that differs by variant
- one
TypeAdapter named for the alias, only for bare arrivals
Forbidden
- a raw-string kind or
kind: Axis unpinned
- an untagged union selected by field shape
match, if/elif, or isinstance over variants
bool returned as a domain decision
- a
RootModel class wrapped around a union
- a routing validator selecting a variant
- a hand-written dict input passed to discriminated construction
Halt Rule
Halt when a variant cannot pin exactly one axis member, when a member sits outside the axis, or when the data that must construct the union carries no identity. Report the row and the variant or arrival: the axis is mis-factored or the arrival belongs to the ordered union, and the table is not finished.