Anatomy
Anatomy specification
What Anatomy Is
Section titled “What Anatomy Is”Anatomy is Proto UI’s structural-semantic system for compound prototypes. It answers: after a prototype is split into stable parts such as root, trigger, content, item, or indicator, how are those parts recognized as one family, what roles do they take, and what structural relations exist between them?
Anatomy is not an information channel. Shared data between components remains Context; component-to-App-Maker capabilities remain Expose; user interaction entering the component remains Event; user-perceivable output remains Feedback. Anatomy handles structural cooperation in compound prototypes, especially role, domain, order, and relation facts that Context alone would express poorly.
It is not an assembler either. Anatomy does not create parts, move parts, materialize missing structure, rewrite templates, or compose other prototypes for the author.
Family Specs
Section titled “Family Specs”An anatomy family is a structural-semantic coordinate system. Stable families should be created at module-static time:
import { createAnatomyFamily } from '@proto.ui/core';
export const SELECT_FAMILY = createAnatomyFamily('base-select', { roles: { root: { cardinality: { min: 1, max: 1 } }, trigger: { cardinality: { min: 0, max: 1 } }, content: { cardinality: { min: 0, max: 1 } }, item: { cardinality: { min: 0, max: 100 } }, }, relations: [ { kind: 'contains', parent: 'root', child: 'trigger' }, { kind: 'contains', parent: 'root', child: 'content' }, { kind: 'contains', parent: 'content', child: 'item' }, ],});debugName is only for diagnostics, debugging, and tooling display. Family identity is the token reference, not the string name.
The family spec must declare the root role. A root claim is the scope anchor for an anatomy domain; without root, runtime queries have no stable scope.
def.anatomy.family(family, spec) is not part of the prototype-author API. Stable library families should not require every part to call a register*Family(def) helper; parts only claim family tokens that already carry canonical specs.
Claims And Domains
Section titled “Claims And Domains”A part claims its role during setup:
def.anatomy.claim(SELECT_FAMILY, { role: 'trigger' });A claim declares structural identity only. It does not create the part, inject behavior, or replace asHook calls. One prototype instance may claim only one role in the same family, and the role must exist in the family spec.
A root claim scopes an anatomy domain:
def.anatomy.claim(SELECT_FAMILY, { role: 'root' });Runtime queries resolve inside the nearest root domain that contains the current instance. The same family may have several independent domains in different positions; queries must not mix parts across domains.
Profiles
Section titled “Profiles”A profile is a named refinement inside the same family. It expresses “this use of the family expects a stricter structure,” but it is not inheritance, derivation, or override.
A profile may:
- tighten cardinality
- add asHook requirements
- add stricter relations
A profile may not:
- relax family cardinality
- delete family requirements
- remove family relations
- turn one family into another family
If a difference cannot be expressed as tightening, define a new anatomy family instead of building an inheritance chain on the family.
Requirements And Diagnostics
Section titled “Requirements And Diagnostics”The only stable Anatomy requirement form in v0 is an asHook check:
roles: { trigger: { cardinality: { min: 0, max: 1 }, requires: [{ kind: 'hook', name: 'asTrigger' }], },}A claim says “I am this role.” A requirement says “a prototype taking this role is expected to have this behavioral protocol capability.” Requirements do not call asHooks automatically and do not inject behavior.
Diagnostics have two levels:
| Level | Default severity | Meaning |
|---|---|---|
| family | error | the core family structure does not hold |
| profile | warning | a named refinement is not satisfied |
Invalid claims, missing valid domains, and family cardinality/relation/requirement failures are family-level problems. Missing profile cardinality, relation, or additional requirement defaults to a warning.
Runtime Query And PartView
Section titled “Runtime Query And PartView”At runtime, a component may query actual parts in the current domain:
const trigger = run.anatomy.partsOf(SELECT_FAMILY, 'trigger')[0] ?? null;const hasContent = run.anatomy.has(SELECT_FAMILY, 'content');Queries return limited PartView objects, not prototype instances or host nodes. A PartView must not expose root targets, adapter targets, or any raw references.
A PartView may read capabilities explicitly exposed by the target part:
const close = trigger?.getExpose('close');If the target part did not expose a key, Anatomy does not infer, fabricate, or access an internal substitute. Anatomy therefore depends on Expose in implementation, but that dependency is “usage of Expose,” not inheritance of Expose’s information-channel identity.
Order View
Section titled “Order View”run.anatomy.order is Anatomy’s host-ordered structural view. It answers how parts in the current domain appear in host-observable order.
const items = run.anatomy.order.partsOf(SELECT_FAMILY, 'item');const index = run.anatomy.order.indexOfSelf(SELECT_FAMILY, 'item');const prev = run.anatomy.order.prevOfSelf(SELECT_FAMILY, 'item');const next = run.anatomy.order.nextOfSelf(SELECT_FAMILY, 'item');The order view is not collection semantics. It is not responsible for item metadata, selection, active item, roving focus, or keyboard policy. Higher-level asHooks may build collection semantics on top of anatomy.order, but anatomy.order itself only provides structural order projection.
version() represents changes to the order signature. It does not represent business data, Expose values, State values, Feedback results, or Template content changes.
Query Policy
Section titled “Query Policy”Ordinary author-facing runtime queries are strict by default: if the current instance cannot resolve a valid domain, the query should fail.
The implementation keeps missing-domain query policy for a few structural projection helpers, such as useCollection returning null or [] during transient structural windows. This is not semantic optionality like context.try*, and it does not mean the anatomy relationship itself is optional.
Contract Previews
Section titled “Contract Previews”Test Mapping
Section titled “Test Mapping”Anatomy coverage is mapped through these test entities:
| Test entity | Main coverage |
|---|---|
T-ANATOMY-0001 | family spec, setup registration, claim rules |
T-ANATOMY-0002 | domain resolution, runtime query, PartView safety, Expose reads |
T-ANATOMY-0003 | profile refinement, asHook requirements, diagnostics |
T-ANATOMY-ORDER-0001 | order view, self index, prev/next, version, privileged missing policy |
These tests turn Anatomy from “compound parts can find each other somehow” into verifiable boundaries: how families are defined, how parts claim roles, how domains are scoped, what runtime may observe, what PartView must not leak, and exactly which semantic layer the order view owns.
Related Specs
Section titled “Related Specs”CoreprovidescreateAnatomyFamily, setup/runtime phases, renderer read view, and shared type boundaries.Contextis the official inter-component information channel; Anatomy is structural-semantic complement, not a replacement for Context.Exposeis the Component → App Maker information channel; Anatomy may read only capabilities explicitly exposed by parts.Templatedefines render output; Anatomy does not create, move, or materialize template structure.asHookmay provide behavioral protocol capabilities required by roles; Anatomy requirements only diagnose whether those capabilities exist.Lifecycledefines availability boundaries for family/claim, runtime query, order query, and cleanup.