Skip to content

ucon.aspects

Aspects: the discriminator that gates combination below the kind layer. An aspect qualifies a quantity on terms its kind cannot express — the weighting standard behind a dose equivalent, the dry/wet basis of a mass fraction. Aspects are tree nodes grouped by family (the tree's root); resolution is family-wise.

See API › Aspects for usage and the Kind-of-Quantity Problem for the conceptual framing.

Aspects: the discriminator that gates combination below the kind layer.

An aspect qualifies a quantity on terms the kind cannot express: two dose equivalents — same dimension, same unit, same kind — may still be weighted per different standards, and their sum conforms to neither. Aspects are tree nodes grouped by family (the tree's root); resolution is family-wise, and the flat-set model this package shipped through v2.1.x (which could not distinguish conflict from absence) is gone.

Design record: docs/internal/decisions/008-aspect-stratum.md.

AspectError

Bases: Exception

Base class for aspect stratum errors.

AspectNotApplicable

Bases: AspectError

An aspect family does not apply to the quantity's kind.

Raised at attachment time — Number(...) construction or formula load — never during resolution. The family attribute is the family root; kind is the offending kind (or None when the family requires a kind and none was given).

AspectRefused

Bases: AspectError

An operation's operands cannot be reconciled within one family.

Two categories share this type:

  • Family conflict — both operands carry positions in the family and the lowest common ancestor's policy refuses the join (left and right are both :class:Aspect\ s).
  • Partial under strict — one operand carries the family and the other is silent (the silent side is None).

The family attribute is the family's root aspect; policy is the join policy consulted. The payload is deliberately warrant-shaped so a future unified refusal can wrap it losslessly.

AspectForest

A collection of aspect trees, one lattice engine per family.

Construction closes over parents (passing leaves is enough), validates root-only fields, and loads each family into its own mirrored :class:KindLattice. All structural failures surface as :class:AspectError.

get(name)

Resolve a name to its aspect; :class:AspectError if absent.

families()

The family roots, one per tree.

family_of(aspect)

The family root governing aspect (registered instance).

lca(a, b)

Lowest common ancestor within one family, with its policy.

Operands from different families are a caller error — resolution groups by family before consulting the engine — and raise :class:AspectError.

join(a, b)

LCA-based join honoring the ancestor's policy.

Equal aspects short-circuit. A refuse ancestor raises :class:AspectRefused carrying the family, both operands, and the policy consulted.

Aspect dataclass

One node in an aspect tree.

Attributes

name : str Node name. Package-declared aspects are fully qualified ("radsafe:icrp103"); root builtins are unprefixed. parent : Aspect | None Parent node; None marks a family root. join_policy : JoinPolicy Policy consulted when two positions in this family meet at this node as their lowest common ancestor. Defaults to REFUSE — strict matching is the zero-configuration behavior; LCA degradation is opt-in per node. applies_to : frozenset[str] Root-only. Kind names this family may attach to, or {"*"} for kind-independent families (coverage factor, calibration status). Checked at attachment, never during resolution. multiplication_policy : MultPolicy Root-only. Behavior under ×/÷; see :class:MultPolicy.

is_root property

True when this node is a family root (and family ⊤).

root property

The family root this node belongs to.

MultPolicy

Bases: Enum

How a family's aspects behave under multiplicative operations.

CARRY Aspects propagate onto the product/quotient whenever either operand carries them — provenance survives multiplication, so refusals outlive kind degradation. The default, and the reason the stratum is load-bearing.

resolve_add_aspects(left, right, *, strict, warn=True, op='Adding')

Resolve result aspects for addition or subtraction.

Family-wise: equal carries, differing joins at LCA under the ancestor's policy, partial refuses under strict and inherits (with a warning, unless warn is false) otherwise.

resolve_mul_aspects(left, right, *, op='Multiplying')

Resolve result aspects for multiplication or division.

Family-wise: equal carries, differing joins at LCA under the ancestor's policy, partial follows the family root's multiplication_policy (carry threads the present positions onto the product). op names the operation in any refusal message; the rules themselves are symmetric.