Designing the data model
Load this card when a task declares or changes App data: named types, fields
and their attributes, Enumerations and Unions, EnumSource choices and keys,
defaults and initialization, Libertas Schema Paths, CopyFrom or CopyTo,
or CacheIdentity drafts; an Endpoint and its protocol also need the
Endpoint protocol card. Its
rules are generated from the data model reference
and the source annotation reference, which own
them. The annotation inventory gives each
annotation's Rust and TypeScript spelling; changing a published protocol or
stored representation also needs the data-type evolution card,
and a field calculation the calculation card.
Order of work
- Choose the types (
types.*,types-only.*,schema.*): App-owned types exported from the App root, foreign types by their owner's FQN, numeric widths and identity scalars. - Declare each attribute where it may stand (
attr.*,annot.*), with its semantic exclusions and value grammar (numeric.*,format.*,bitflags.*,mime.*). Chart attributes (chart.*,annot.chart*) are on the chart card and the 3D chart card. - Shape choices and alternatives (
union.*,key.*,enumsource.*,protocol-variant.*,baseobjects.*,data-schema.*). - Decide initial values (
init.*,defaults.*,user.*,fixed-user.*). - Write paths and copies (
paths.*,copy.*); the shared copy rules apply to ordinary and calculation copies alike. Display Template selectors (display.selector.*) are on the Display Template card. - Declare draft-recovery metadata (
cache.*), and keep runtime values and localized documents in step (validation.*,docs.*). Endpoint and protocol declarations are on the Endpoint protocol card. Then compile with Studio and fix every reported rule.
Rules to apply
Studio does not check these rules. Each is quoted from its owner.
Libertas source annotation reference
Owner: annotations.md#libertas-source-annotation-reference
annot.canonical-spellings-only: Use only the canonical spellings shown here. Compiler acceptance alone does not establish supported schema syntax.annot.placement-is-authoring(judgment): The placement column below states the public authoring placement; it is not permission to move an annotation merely because a parser can preserve it for a later Studio error.annot.documentation-invariants: Every annotated declaration and nested schema-visible node must also follow the schema documentation invariants, including the user-friendly label/description, member, variant, and List-item rules.annot.comments-domain-meaning(judgment): Source comments supply domain meaning without duplicating those generated notes. Rows marked "compiled into the Display Template" are presentation attributes: Studio validates them, compiles them into the package's Display Template as its lowest-specificity rules, and omits them from the final schema. Adisplay.jsonrule can change their effect per device without editing source.annot.catalog-scope(judgment): This catalog exhausts schema-parser annotations, not unrelated SDK runtime functions or serialization derives such asLibertasAvroEncode,LibertasAvroDecode,VariantIndex, orvariant_index!; those remain covered by the public SDK and the language guides.
Package, discovery, and parser helpers
Owner: annotations.md#package-discovery-and-parser-helpers
-
annot.export.helper-only:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasExport#[libertas_export]on a public function;#[derive(LibertasExport)]on a schema struct/enumParser/compiler helper Enables the language's public App wrapper or helper attributes. It emits no portable Exportattribute and does not replace the native public/export requirement.TypeScript guide, Rust guide -
annot.export.union-content:TypeScript canonical source Rust canonical source Public placement Result and meaning Details Not applicable Exact Union rustdoc line /// #[libertas_export(content = "payload")]Rust Union declaration Emits parser-owned UnionContentNamerepresentation metadata. Do not inventtagoruntaggedforms.Rust guide -
annot.const-enum.file:TypeScript canonical source Rust canonical source Public placement Result and meaning Details File-leading /** @LibertasConstEnum */Not applicable Dedicated TypeScript file containing one documented exported numeric constant per statement Treats the constants as members of the numeric Enumeration exposed by a documented exported typeofnamespace-import alias in the App entry module.TypeScript enumerations
Defaults, constraints, and ordinary presentation
Owner: annotations.md#defaults-constraints-and-ordinary-presentation
-
annot.enum.use-native-enum:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasEnum(A, B, C)#[libertas_enum(A, B, C)]Applicable String alias/field or Enumeration declaration supported by that language Defines a catalog using positional members. The parsers currently cannot attach source documentation to those fabricated members, so codebots must use a documented native numeric enum instead and must not generate this otherwise public compatibility form. TypeScript values=[...]is not canonical syntax.TypeScript enumerations, Rust attributes -
annot.enumsource.unmatched-unanswered:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasEnumSource("$.choices")#[libertas_enum_source("$.choices")]Unsigned integer field/type; the key's String or integer type when the target List declares a key; or a List of that type Emits EnumSource; the host stores the zero-based index of an item in the resolved same-tree List or, when that List's member declares aKeyfield, the chosen member's key value. A stored value matching no current member is unanswered and never remapped. An unanswered non-Nullable host whose source offers exactly one selectable member takes that member. A List host stores several distinct chosen indices or keys.Common field metadata, EnumSource keys, EnumSource List hosts -
annot.combinations-not-implied(judgment): Attribute combinations and inherited effective metadata are validated by Studio. Do not infer that two annotations can coexist merely because they have separate rows in this catalog.
External types, Matter descriptors, and Union metadata
Owner: annotations.md#external-types-matter-descriptors-and-union-metadata
-
annot.device-type.generated:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasDeviceType("descriptor")#[libertas_device_type("descriptor")]Effective LibertasDevicefieldEmits the Studio-generated physical Matter DeviceTypedescriptor. Do not invent the encoded descriptor manually.Matter -
annot.virtual-device-type.generated:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasVirtualDeviceType("descriptor")#[libertas_virtual_device_type("descriptor")]Effective LibertasVirtualDevicefieldEmits the Studio-generated VirtualDevicedescriptor. Do not invent it manually.Matter -
annot.discriminator.typescript-only:TypeScript canonical source Rust canonical source Public placement Result and meaning Details @LibertasDiscriminator("kind")Not applicable TypeScript discriminated Union when automatic detection is ambiguous Emits parser-owned UnionTagName. Normal TypeScript literal/enum discriminators are detected automatically; Rust uses enum declaration order and native representation.Protocol roles
Inferred and generated metadata: never invent source annotations
Owner: annotations.md#inferred-and-generated-metadata-never-invent-source-annotations
-
annot.generated.no-source-spelling: The final schema contains attributes and fields that are inferred from native source or generated from one of the public annotations above. Their presence in schema JSON does not create another public macro or decorator. -
annot.no-std.native:Generated or parser-owned result Source of the result Rust no_std=trueNative crate attribute #![no_std], not a Libertas helper macro. Use it only when the App and all dependencies support that build model. -
annot.generated.no-derived-spellings: Never derive a new@Libertas...or#[libertas_...]spelling from a schema JSON property.
Not public or not usable
Owner: annotations.md#not-public-or-not-usable
annot.removed.never-emit: Codebots must not emit any spelling in this section.
Unsupported authoring forms
Owner: annotations.md#unsupported-authoring-forms
annot.named-argument-variations: Named-argument variations do not create additional supported spellings.
Removed Rust SDK helpers
Owner: annotations.md#removed-rust-sdk-helpers
annot.rust-sdk-helpers.removed: The SDK helper allowlists no longer admitlibertas_string,libertas_array, orlibertas_cacheable, because the owning schema parser does not support those source forms. Uselibertas_sizefor size bounds and the documented CacheIdentity behavior where needed.libertas_discriminatoris also not a Rust schema annotation; Rust uses native enum representation.
MIME-aware Bytes annotation
Owner: annotations.md#mime-aware-bytes-annotation
annot.mime-types.semantic-choice(judgment): Keep unannotated Bytes fields for raw binary protocols;MimeTypesis a semantic choice for media values, not a replacement for ordinary Bytes.
CacheIdentity
Owner: annotations.md#cacheidentity
cache.clients-implement: Use clients that implement this attribute; older client binaries do not provide draft recovery.
Eligibility and field placement
Owner: annotations.md#eligibility-and-field-placement
cache.identity.tuple: Multiple marked fields form one identity tuple. All must match; they are not alternative identities. The client does not infer identity from field names, Hidden, or CopyFrom.cache.identity.defined-immutable: Identity values must be defined after initialization; valid null is allowed and differs from undefined. They remain immutable for the editor lifetime, including against user edits and calculation writes. Restoring editable data preserves the freshly initialized identity values.
Identity, revisions, and application responsibility
Owner: annotations.md#identity-revisions-and-application-responsibility
cache.identity.distinguishing-context(judgment): The application must supply enough distinguishing context to prevent one workflow's draft from matching another workflow. A workflow identifier is a typical choice.cache.identity.revision-recommendation(judgment): Recommendation: include an application-maintained data/workflow revision when changes to saved data invalidate earlier drafts. For example, a historical page edit may invalidate later pages; changing their identity revision prevents restoring obsolete local drafts. The client does not infer these dependencies.
Required design principle
Owner: app-contract.md#required-design-principle
app.design.natural-data-model(judgment): Model data in its natural form. Declare each stored type as what the data is: its real fields, one owner per fact, and a Union where a value is one of several shapes. Never reshape stored data for a screen, a workflow step, or a question order. Human-facing types, the Request and Response payloads a person edits and views, are views of that data: they may wrap it as the person's path needs, for example as a wrapper member within a Union, while the stored model stays as it is.app.design.no-contradiction(judgment): The two never conflict. The goal is human first, and the natural data model serves it: the platform presents the model in its natural form along the person's shortest path, so neither is traded for the other. Where they seem to conflict, the platform is missing a presentation mechanism; raise that gap instead of bending the data or lengthening the person's path. Presentation and interaction adapt to the model through the platform: schema attributes such asAskOnAdd,ReadOnly, andHidden, and Display Template rules such aslock,flatten,promote, and layouts. When the platform has no way to present a natural model, that is a platform gap to raise, not a reason to bend the data.
Libertas data model reference
Owner: schema.md#libertas-data-model-reference
schema.generated-by-studio: Generate schemas through Studio rather than editing them.
Libertas Schema Path
Owner: schema.md#libertas-schema-path
paths.native-names: Fields use case-sensitive Native Names, not localized Display Names. Named type references and inheritance are resolved without introducing extra value-tree levels.paths.context.operation-source: An operation-specific copying source does not implicitly replace the interaction's reference context.
Shared CopyFrom and CopyTo rules
Owner: schema.md#shared-copyfrom-and-copyto-rules
copy.alternatives.source-order: For each annotated receiving node, CopyFrom visits reference objects in context order. Within each object, it evaluates the comma-delimited alternative paths in declaration order. It skips absent/undefined values and stops at the first available value, including valid null. Source order takes priority over path order: exhaust the paths in the first object before trying any path in the next.copy.selection.single-source: Selection is independent for each annotated receiving node. A selected composite value is projected from that one source; do not merge reference objects or fill its absent members by searching another object.copy.unavailable.no-copy: With no reference objects or no available path, CopyFrom performs no copy. Ordinary request construction then uses the normal initialization rules below.copy.paths.explicit-qualifiers: An explicit path may address a node at a different nesting depth or with a different Native Name. Type or Protocol Variant qualifiers identify the permitted schema context; a compatible type alone does not identify the intended value. Within a copied Table, corresponding members retain exact, case-sensitive Native Name matching. Selecting a differently located Table does not implicitly rename its members; such a difference requires an explicit mapping of the relevant node where permitted, or a payload with corresponding member names.copy.projection.native-names: Both CopyFrom and CopyTo use the same reduced-field projection rules. Match record fields by exact, case-sensitive Native Name and recurse through records and array elements. Source-only fields absent from the destination type MUST be ignored without a copy error; they are not assignments and do not participate in destination compatibility, overlap, or protection checks. Matching fields retain the applicable type, nullability, semantic scalar, and Union identity requirements. This does not make a required destination field optional or permit an incompatible matching field.copy.projection.null-and-validity: A valid null assigns null to a nullable destination; it does not mean unchanged. A received CopyTo payload must remain valid under its own schema. CopyFrom may project an unfinished editor under the destination's completeness rules.copy.naming.shared-roles(judgment): Design rationale: structural matching by field name. Because copied records match members by Native Name and ignore source-only fields, a Rust or TypeScript App composes values the way a scripting language does: any record with a member of the expected name and a compatible type can supply or receive it, whatever its declaring type. A calculation input can list@.Business.assets,@.Farm.assets,@.Rental.assets, and each branch's rows project into the input's element type because every branch names that memberassets. A field name is therefore part of an App's interface, not only a label. Name fields that play the same role across types deliberately and identically, and fields with different meanings differently; one calculation, projection or alternative list then serves every type that shares the role, with no adapter types.copy.initialization.unaffected-nodes: CopyFrom and CopyTo override initialization only at the nodes they actually assign. On a newly constructed destination, every unaffected node retains its ordinary Fixed, Default, localized default, nullable, and type initialization. This includes destination-only fields within a copied Table or array element.
Ordinary initialization
Owner: schema.md#ordinary-initialization
init.ordinary: Ordinary initialization may yield a value, valid null, or undefined; it need not make the constructed request complete. Type initialization, which applies to a node with no Fixed, Default, or localized default, is the same on every client. An editable Nullable node is undefined, unanswered like a Union with no branch selected, because its editor asks a two-answer question (Nullable choices); the reserved Default$nullstarts it at null, a complete answer, and any other Default starts it at that value. A ReadOnly, Hidden, or Fixed Nullable node, which the person cannot answer, is null, and so is a Nullable node of a Response or SubscriptionData payload. A Table is its fields, each initialized by these rules; a List is empty; a Union has no selected branch. Every other required node is undefined, which is unanswered: a String, a number, a Boolean, an Enumeration, Bytes, a DateOnly, a TimeOnly, and a DateTime alike. A client never supplies an empty string, zero, a range bound, or the current time in its place, so a present value always means an answered one. Merely supplying a reference context does not change an unaffected node's initialization.copy.initialization.existing-destination: On an existing destination, unaffected nodes keep their current values; copying another field does not reset them.
Shared CopyFrom and CopyTo rules
Owner: schema.md#shared-copyfrom-and-copyto-rules
copy.union.initial-branch: CopyFrom on a Union selector may supply its initial branch. Browsing or explicitly choosing another branch does not reapply that selector's CopyFrom; the chosen payload and its descendants retain their own ordinary construction, including their CopyFrom mappings and the current reference context.copy.fixed.member-precedence: Within a copied Table or array, a copied member takes precedence over a Fixed initializer, but still has to satisfy the Fixed constraint and every other applicable constraint. Copying does not waive destination protections such as the calculation CopyTo prohibition on overwriting Fixed fields.copy.apply.construct-or-merge: The operation defines how the projected values are applied. CopyFrom constructs its destination; CopyTo merges into an existing destination. Source selection, destination uniqueness, array correspondence, and operation ownership retain their respective contracts.
Context and syntax
Owner: schema.md#context-and-syntax
-
paths.context.prevrequest:Usage Accepted form Source or destination context CopyFrom when constructing a PrevRequest action The same variant-rooted or root-relative copy syntax The construction context contains the current edited request as its reference object. -
paths.context.loader:Usage Accepted form Source or destination context Display Template leading-page loader CopyFrom The same variant-rooted or root-relative copy syntax Initial load uses the current complete editing Request as the construction reference object, without changing its server-supplied interaction reference context. Subsequent refresh uses the current leading page under the ordinary rules. See master-detail panes.
Typed ancestors and bound occurrences
Owner: schema.md#typed-ancestors-and-bound-occurrences
paths.binding.invoking-node: A link binds self-or-ancestor from its invoking node, the tapped node or the host field, so^<TopicRow>on a link declared byTopicRowselects that row. EnumSource and request-field ConstrainedBy bind only occurrences on the host field's ancestry, starting at its parent and including the variant root; the variant root remains eligible when it is the host, which makes primitive variant roots addressable. A strict path pins the schema occurrence; relaxed matching selects the nearest enclosing occurrence of its named type. The selector may omit a suffix to select the bound value itself; otherwise suffixes use ordinary fields and literal zero-based array indices.$still selects the complete current request where the context table admits it; calculation paths reject it and write the request root as^<Variant>. Ordinary CopyFrom uses each reference object in context order as a candidate variant root.
Current-data references in validation expressions
Owner: schema.md#current-data-references-in-validation-expressions
paths.validation.missing-null: If a path exists, it resolves to its value; otherwise, it resolves to null. Resolve segments over actual values in source order:
Availability, null, and interaction ownership
Owner: schema.md#availability-null-and-interaction-ownership
paths.context.attribute-defines-syntax(judgment): Reference-context lookup is a shared schema reference capability. Any schema attribute whose semantics support reading a referenced value may use this context when its contract permits it. Each attribute defines its accepted path or expression syntax, expected value type, and handling of an unavailable reference; this capability does not make every attribute accept a path. The interaction reference-context rule owns the server-supplied context and its replacement.paths.context.no-implicit-fetch: A reference lookup never performs an implicit server fetch or substitutes task parameters, sibling request values, task-upgrade data, pooled endpoint data, or another interaction's reference context.paths.validation.curly-lookup: Curly validation references visit reference objects in the same context order. Within each object, they inspect comma-delimited paths in declaration order and return the first non-null value. Missing, undefined, and null alternatives are skipped, continuing into later objects when necessary; no match yields null. They are pure reads. Unlike CopyFrom, a valid null does not stop this lookup. With no reference context, including first-time composition, every such read yields null; authors must handle that absence. CopyFrom follows the distinct copy-selection and initialization rules. Studio checks their syntax but treats their result type as schema-unknown and nullable because server-supplied reference-object schemas may differ.paths.validation.rule-roots: Editable-request rules use the interaction's current reference context through curly references. Function rules see the argument Table; a field/type rule is rooted at its owner. A required field can be temporarily unanswered locally, but a valid path expression does not make it optional or permit an incomplete transmitted request. EditRequest construction follows the interaction reference-context rule.paths.validity-not-permission(judgment): A syntactically valid path does not grant permission, create a missing value, prove a runtime index exists, or transfer ownership of a pending reply. The containing attribute defines assignment, validation, and lifecycle behavior. ConstrainedBy, EnumSource, BaseObjects, and calculation rules retain those operation-specific requirements in their owning sections.
1. Artifact model
Owner: schema.md#1-artifact-model
schema.artifact.native-name-stable: The separation is deliberate.NativeNameremains a stable programmatic name in the schema, while localizedDisplayName, fieldName,Description, and packageStringResourcesvalues live in documents. Translating presentation text therefore does not break type references or other schema links.
2.1 Top-level collections
Owner: schema.md#21-top-level-collections
-
schema.dependencies.studio-generated:Field Meaning AppDependenciesStudio-generated complete flattened logical App dependency lock. Each entry carries a canonical package identity and the exact Hub App version whose schema was used for this deployment. Versionis required and identifies that exact version. -
schema.types.owned-only:Field Meaning TypesNamed types whose declarations are owned by this App. A type declared by another package is never copied here, even when it is imported, used, or re-exported locally. -
schema.functions.exported:Field Meaning FunctionsExported callable functions that are not explicitly ignored. Functions are identified by NativeName; parameters are positional and retain source order. -
schema.functions.no-return-schema(judgment): The generated function model contains parameters but no return-schema field. Request/response flows are modeled through endpoint protocol unions and persistent function data through a function data-schema union.
2.3 Type-node fields
Owner: schema.md#23-type-node-fields
-
schema.nativetype.not-wire:Field Meaning and invariant NativeTypeNative-language type metadata. The Rust parser records concrete types such as u16; the TypeScript parser normally emits an empty string. Shared validation initializes a missing value to"". Wire behavior is defined byTypeand wire-affecting attributes, not by this field.
2.4 Runtime types
Owner: schema.md#24-runtime-types
types.identity.signed-ids: System identity scalars (User,Device,LanDevice,VirtualDevice, andEndpoint) use signed 64-bit IDs: Rusti64and TypeScriptbigint.Useralso represents groups. Durable allocated IDs are positive; negative IDs are runtime dynamic identities and are not durable references. Zero and other sentinels have only their operation-specific meanings. The semantic type already defines the width and signedness; noNumberTypeattribute is needed.types.number.integer-step-default: Integer nodes default toNumberStep=1in parser paths that construct integer constraints.types.number.cross-language-width: A cross-language contract must use a width supported by both representations.
2.5 Structural order and IDs
Owner: schema.md#25-structural-order-and-ids
schema.order.source-order: Table fields, function parameters, list elements, and union variants preserve parser/source order. This order is part of the wire contract.schema.ids.ts-enum-local-counter: TypeScript enum-member IDs use an enum-local counter beginning at zero and do not consume the surrounding tree's sequence. The Rust parser currently applies its ordinary depth-first allocator to enum members. Cross-language tooling maps IDs through verified structure rather than assuming the two native schemas use identical enum IDs.schema.ids.local: An ID is meaningful together with its owning function/type document. It is not a substitute for a canonical type identity.schema.order.preserve-children: Top-level sorting never sortsChildren; it therefore cannot alter wire order.
3.2 Foreign wire types
Owner: schema.md#32-foreign-wire-types
types.foreign.fqn-grammar: Bothdeveloperandpackageuse lowercase snake case, separated by exactly one hyphen.TypeNameis a source-language identifier-like simple name.types.foreign.fqn-external: For every externally owned reference, this complete FQN is stored directly inType,Heritages,Bitflags,ForeignTypeSchema,ProtocolSchema, orFunctionDataSchema, depending on the reference site. Every such FQN contributes its package to the direct dependency set used for pre-deployment Hub exploration and the finalizedAppDependenciesclosure. An FQN always means external ownership, so its package component must differ from the package that owns the referencing schema; local references use the simple type name.
3.3 Native compiler metadata
Owner: schema.md#33-native-compiler-metadata
schema.native-metadata.no-external-copies: Final artifacts contain each local named type once and external references as owning-package FQNs. They do not embed copied external type definitions or transient resolution/source-location metadata.NativeTypedoes not independently change wire bytes.ExternalNativeTypeis removed; native imports resolve declarations while serialized references keep their actual owner.
4.3 Value, constraint, and presentation attributes
Owner: schema.md#43-value-constraint-and-presentation-attributes
-
attr.nullable:Attribute Meaning NullableThe value may be absent/null. Optional source types normalize to this marker. -
attr.ask-on-add:Attribute Meaning AskOnAddMarker value true: the person's Add asks this List-member value first, and adds no member without it. Only the person's Add; other writers are unaffected. See add-time values. -
attr.read-only:Attribute Meaning ReadOnlyValue is displayed but not user-editable. Initialization, CopyFrom, EditRequest, calculation or link-return CopyTo and draft restoration still write it; only Fixedprotects a value. See the ReadOnly rule. -
attr.hidden:Attribute Meaning HiddenValue is hidden from ordinary editors. On a chart carrier table, composition, or chart-bearing Union variant wrapper, it also marks direct non-chart fields as preserved transaction context that renderers exclude from chart projection. -
attr.time-interval:Attribute Meaning TimeIntervalDisplays a numeric value as a duration. It does not create a distinct wire type. -
format.presentation-only:Formatis valid only on the four effective hosts above and may be inherited through a named type. On an ordinaryNumberit follows the exclusions of numeric semantic attributes; on aDateOnlyNumber it uses date-pattern grammar. It may coexist withPhysicalUnit, in which case it formats only the numeric portion and the unit remains separate localized semantic metadata. Money uses the exact currency editor. Other editors retain native number/date/time controls and may show a formatted preview. Renderers applyFormatonly at presentation boundaries—labels, summaries, table cells, tooltips, chart ticks, and accessibility text. Parsing user input, Avro payloads, defaults, bounds, sorting, grouping, chart geometry, cache keys, and protocol compatibility always use the raw scalar. -
attr.function.singleton-hub-check:Singletonis function metadata because a task instantiates a function, not a package. The Hub identifies the function by App ID plusNativeName, independent of the selected App version. Creating, retargeting, or changing the version of a task is rejected when another task has the same function identity and either selected function schema carriesSingleton=true. An update may replace its own task record. Checking both schemas prevents an older non-singleton version from bypassing an already installed singleton declaration. -
bitflags.runtime.allowed-mask: A field'sDefault,Fixed, task configuration value, outgoing runtime value, and received runtime value may contain any combination of declared nonzero bits and no undeclared bit. -
bitflags.catalog-materialization-and-ui: Studio fetches that package from the selected Hub during deployment planning, materializes its catalog and localized document for validation/UI, and records its authoritative version in the finalAppDependencies. Documents localize Enumeration members in the normal way. Read-only surfaces join the selected localized names with,; editors use a multiple-choice chooser, one checkbox per nonzero member, and encode the bitwise union of the choices. The zero member is never a choice: leaving every box unchecked is the empty selection0, and the zero label is shown only as the read-only text of an empty selection. -
numeric.format-coexists:Formatmay stand withDateOnly,Money, orPhysicalUnit: it then formats the date, the amount, or the numeric portion.
Reserved Default values and constant references
Owner: schema.md#reserved-default-values-and-constant-references
defaults.pattern-dollar-literal:Patternaccepts a whole source constant argument through its source-language syntax. Inside a quoted pattern,$remains regex text; decoded patterns are never scanned for constant references. The emitted attribute contains only the decoded pattern.
User and group defaults
Owner: schema.md#user-and-group-defaults
user.no-implicit-current-user:Userstores a user or group ID. Neither aUsernor aList<User>implicitly selects the current user, including when only one picker candidate exists. WithoutDefault, ordinary initialization applies, including undefined. Copying retains the shared initialization precedence.
Fixed current-user security constraint
Owner: schema.md#fixed-current-user-security-constraint
fixed-user.first-field(judgment): Recommended declaration order: declare oneFixed("current-user")field as the first payload field of each Request or SubscriptionRequest variant, and reuse that verified identity in App code. This keeps the identity near the start of the payload after any protocol variant selectors. First position is a recommendation, not a schema requirement; nested protocol variants and identity fields within nested request values remain supported, excluding Lists. If additional fields carry this constraint, the Hub MUST validate every applicable occurrence; validating the first never exempts later fields. Declaration order enables efficient identity checks but does not guarantee that a Hub implementation decodes only one field.fixed-user.hub-verifies: Before invoking App code, the Hub MUST compare the submitted value with the user identity established by authentication for that invocation. It MUST reject a mismatch, null, an unresolved identity, or malformed input. It MUST NOT repair a submitted mismatch by replacing the value. Client autofill, ReadOnly, Hidden, labels, and a claimed user ID in the payload are never evidence of identity.user.notification-recipients: For mandatory notification recipients, combineDefaultwith staticReadOnly: on a scalar User it protects that ID; on a List it protects membership and order, so mark the User item type ReadOnly as well to protect each recipient ID. Follow the ReadOnly placement rules. An unresolved explicit default blocks submission even when ReadOnly; never silently substitute recipients.
MIME-aware Bytes
Owner: schema.md#mime-aware-bytes
mime.validate-content: An App must validate actual content when the declared MIME label matters to its processing or security.mime.empty-undefined: Zero-lengthBytesmeans media undefined. It is a present and valid wire value, including on a non-Nullablefield. A server may send it; clients show no selected media. It is distinct from nullable null and from a validLMB1value with zero content bytes. For ValidationRules, zero-length MIME-aware Bytes evaluates as null; ordinary Bytes retain their existing valuation. A mandatory media field needs an explicit rule such as[] != null : "IMAGE_REQUIRED";.SizeMinandSizeMaxrun only for defined media and measure content bytes, excluding the LMB1 header. ThusSizeMin=1rejects a defined empty file but does not require a file to be selected. Transport limits count the entire sequence.mime.compatibility:MimeTypeschanges the semantic Bytes type without changing the Avro primitive. Raw and MIME-aware Bytes are not implicitly compatible. A producer MIME filter is compatible with a recipient only if every exact type it admits is accepted by the recipient; dynamic values are checked against the destination at runtime. Copies preserve the complete envelope; clients do not guess or transcode media from a filename or destination filter. AddingMimeTypesto an existing raw field requires a new immutable App version. Legacy mobile-Hub paths retain their raw Bytes behavior.
5.1 Tables and inheritance
Owner: schema.md#51-tables-and-inheritance
types.table.inheritance: ATableis an ordered record. Each child is one field. A derived table can list base types inHeritages; inherited children are resolved recursively and added unless the derived table already declares the sameNativeName.
5.2 Lists
Owner: schema.md#52-lists
types.list.element: AListcontains one child schema describing every element. The element may be a built-in node, an inline composite, or a named reference. List-level and element-level documentation are distinct even though both originate around the same source declaration.
6.3 Function data schemas
Owner: schema.md#63-function-data-schemas
data-schema.key-layout: The key union and its complete reachable layout are ordinary entries inTypes, including nested unions, ordered fields, discriminator values, numeric representations, byte bounds and nullability. There is no separate index catalog: fields in a key define its identity and ordered scan dimensions. Stored records and concrete index values are runtime data, not schema content. The generated default document includes the key union, its nested types and their field/variant text under the ordinaryTypesdocument collection. Translations change those labels, never encoded keys.
7. Path-based object and choice binding
Owner: schema.md#7-path-based-object-and-choice-binding
enumsource.keyed-bounds:NumberMin,NumberMax,NumberStep,RangeMin, andRangeMaxon a keyed integer host bound the stored key value, never the member's row position. A member whose key is unset (null) or an emptyStringis not offered and cannot be selected.ConstrainedByconstrains a host's stored value, which for a keyed host is the key. Allowed sets are integers andConstrainedByapplies only to Enumeration and Union fields, so Studio's existing rule already rejects it on aString-keyed host.
Enumsource list hosts
Owner: schema.md#enumsource-list-hosts
enumsource.list-host.stale-elements: Every element must name a selectable member. An element naming none, a stale key included, is unanswered: the host blocks submission with a field error, as a stale scalar host does, and is never remapped or silently dropped.enumsource.list-host.distinct: Elements are distinct by this contract, so the host needs noUnique: a repeated key or index blocks submission with a field error.enumsource.list-host.empty-and-size: The empty List is a complete answer: none chosen.SizeMinandSizeMax(Size(min, max)) bound the number of chosen keys, soSizeMin=1requires at least one.enumsource.list-host.element-bounds: Numeric bounds and step on the element type bound each stored key or index, as on a scalar host.enumsource.list-host.no-singleton: The singleton rule never fills a List host, and a Display Templatewhen_single_choicerule cannot select one.ConstrainedBydoes not apply, because the host is not an Enumeration or Union field.
8. Types-only and interoperable packages
Owner: schema.md#8-types-only-and-interoperable-packages
types.compatible.merged-view: At runtime the consumer resolves the official schema, validates structural wire compatibility, and creates a transient merged view. Official attributes provide the base at every corresponding node; attributes present on the corresponding compatible schema node override them by name. The persisted compatible schema is never rewritten. The final merged graph receives the normal contextual attribute validation. Document projection uses the same structural ID mapping while preserving language-native nodes with no official counterpart, such as a TypeScript-only discriminator field. Package-level display text remains owned by the compatible package.
9. Static and runtime validation
Owner: schema.md#9-static-and-runtime-validation
validation.task-value-phase: Task-value validation is a separate phase. It applies the generated model to actual values and checks nullability, scoped uniqueness, endpoint base objects, enum membership, numeric type/range/step constraints, string and byte lengths, list size, and table structure. Schema validity does not imply that every runtime value is valid.
10. Localized package documents
Owner: schema.md#10-localized-package-documents
docs.string-resources-package-only: PackageStringResourcesstores notification, data-name, permission-reason,FormattedText, and chart templates by stable package-local key. Function and type documents have no resource table. A protocol peer already knows the task's App package and therefore needs no type-owner metadata or resource FQN.schema.names.identity-versus-localization: This is why schemaNativeNamevalues must remain stable while natural localized names belong in the document.
11.1 Deterministic sorting
Owner: schema.md#111-deterministic-sorting
schema.sorting.children-unsorted: It intentionally does not sortChildrenor function parameters. Key variants and key fields therefore retain their declared binary order; sorting is idempotent and never rearranges a key layout.
11.2 Schema equality
Owner: schema.md#112-schema-equality
schema.equality.structural-versus-strict: Structural equality resolves named references recursively and compares effective runtimeType, attributes when requested, and ordered children. IDs,NativeType, and ordinary field/type names do not define non-strict structural equivalence. Function names must match. Strict equality additionally requires the resolved and reference-nodeNativeNamevalues to match.
11.3 Revision digest
Owner: schema.md#113-revision-digest
schema.digest.final-schema:Revision.ContentSha256has the formsha256:followed by 64 lowercase hexadecimal characters. It covers the final schema only, after presentation attributes have moved into the Display Template, so a template change never changes it. Studio computes it by:
Rules Studio enforces
Studio rejects a source that breaks one of these rules. The owner holds the full rule.
Package, discovery, and parser helpers
Owner: annotations.md#package-discovery-and-parser-helpers
annot.default-locale.placement: DefaultLocale goes once in the entry file package documentation; omission means en
Function-level task declarations
Owner: annotations.md#function-level-task-declarations
annot.permissions.placement: Permissions resolves one positional constant on a public App function or server Endpoint fieldannot.function.no-other-attributes: Functions accept only the public function attributes, never field, protocol-role, chart or Matter annotations
Eligibility and field placement
Owner: annotations.md#eligibility-and-field-placement
cache.identity.placement: Mark only direct fields of the request root record; nested, array and Union-branch fields cannot carry CacheIdentity
MIME-aware Bytes in workflow drafts
Owner: annotations.md#mime-aware-bytes-in-workflow-drafts
cache.mime.not-identity: MimeTypes cannot occur within a CacheIdentity field
Common field metadata
Owner: presentation.md#common-field-metadata
field.ask-on-add.placement:AskOnAddgoes on a field with a value of its own in a List member Table, or on a List whose member has one; never Hidden, ReadOnly, Fixed or OutputOnly
Shared CopyFrom and CopyTo rules
Owner: schema.md#shared-copyfrom-and-copyto-rules
copy.fixed.no-copyfrom: A field cannot combine Fixed and CopyFromcopy.copyto.exactly-one-match: Exactly one CopyTo destination matches; several matches are rejected before any assignmentcopy.types.compatible: CopyFrom and CopyTo require compatible receiving types and preserved operation ownership; runtime checks actual values, bindings and unresolved ambiguity
Context and syntax
Owner: schema.md#context-and-syntax
paths.context.enumsource-baseobjects: EnumSource takes one$,@,^or typed-ancestor path; BaseObjects a comma list of$,@or^pathspaths.context.llmdoctrans-validation: LLMDocTrans validation takes one$,@or^path to a Table of the edited Requestpaths.context.ordinary-copyfrom: Ordinary CopyFrom takes strict^<Variant...>,$or&alternatives read from the interaction reference contextpaths.context.link-bound-occurrence: On a Response or SubscriptionData link target a typed selector names the tapped node's bound occurrencepaths.context.link-copy: Request-editor link CopyFrom and link-return CopyTo bind from the host field's occurrencepaths.context.appendto: AppendTo takes exactly oneVariant.fieldnaming a root array of an admitting SubscriptionDatapaths.context.appendindex: AppendIndex takes exactly one root-field$.fieldcontrol fieldpaths.context.constrainedby: ConstrainedBy takes one root-relative path, or on a request field a^or typed-ancestor pathpaths.context.reduced-subscriptiondata: Reduced SubscriptionData CopyTo takes strict^<StableVariant...>destinationspaths.context.current-data: Square validation references read the owner's evaluation root or a bound cursorpaths.context.external-reference: Curly validation references take dot-only{$.path}alternatives from the reference contextpaths.host-relative.syntax: Host-relative paths use.nameor bracket children;$is the root,@the host, each^an actual parentpaths.copy.grammar: Copy-path indices are literal non-negative integers and identifiers ASCII; no quoted bracket namespaths.copy.strict-variant-rooted: Strict^<Variant...>copy paths name every schema level, including selected nested Union branches
Typed ancestors and bound occurrences
Owner: schema.md#typed-ancestors-and-bound-occurrences
paths.typed.host-field-selectors: EnumSource and request-field ConstrainedBy selectors resolve to one parent-relative path for every host occurrencepaths.typed.link-bound-occurrence: Ordinary CopyFrom accepts a bound occurrence only on a Response or SubscriptionData link target
Current-data references in validation expressions
Owner: schema.md#current-data-references-in-validation-expressions
paths.validation.parent-prefix: A leading^run ascends from the annotated value, only at the start and never above the data rootpaths.validation.whitespace: Whitespace around segments and references is ignored; no index expression is evaluated
2.4 Runtime types
Owner: schema.md#24-runtime-types
types.action.unsupported: The reservedActiontype is unsupported in App sourcetypes.number.widths: Numbers carryNumberType: TypeScript names the width and Rust derives it from the native type
3.1 Local named types
Owner: schema.md#31-local-named-types
types.local.root-exported: Every App-owned type is publicly exported from the App root under exactly its declaration name
3.2 Foreign wire types
Owner: schema.md#32-foreign-wire-types
types.compatible.placement:ForeignTypeSchemagoes only on a published named compatible type and names a non-compatible official FQNtypes.compatible.studio-validates: Studio validates a compatible type's placement, external official target and structural compatibility
4. Attribute model
Owner: schema.md#4-attribute-model
attr.known-names-only: Studio rejects an attribute name that neither this reference nor the annotation reference lists
4.2 Function attributes
Owner: schema.md#42-function-attributes
attr.function.singleton:Singletonis the exact markertrueon a function: at most one task per Hubattr.function.data-error-status:DataErrorStatusis the exact markertrue, valid only on a function
4.3 Value, constraint, and presentation attributes
Owner: schema.md#43-value-constraint-and-presentation-attributes
attr.default:$nullis a Default only on a Nullable field; a Union Default names one of its variantsattr.number-bounds: Numeric bounds and step go on Number or DateTime; DateTime requiresu64; the step counts from the minimumattr.length-retained:LengthMinandLengthMaxare retained legacy bounds; current source usesSizeMinandSizeMaxattr.size:SizeMinandSizeMaxbound a List count, String UTF-8 bytes or Bytes length; a Table is no hostattr.unique:Uniquegoes on a non-composite host with an integer level of at least one; the default is99attr.unordered:Unorderedgoes only on a Listattr.suppress-label:SuppressLabelgoes on a scalar, Table or Union, or on a List whose member is a Tableattr.date-only:DateOnlyis the markertrueon an integer Number holding ayyyyMMddcalendar dateattr.bitflags:Bitflagsmarks a fabricated Enumeration catalog, or names one on an integer Numberattr.mime-types:MimeTypesgoes on an effective Bytes host, never with FormattedText or inside a CacheIdentity fieldattr.physical-unit:PhysicalUnitis one canonical CLDR identifier on a Number and never changes raw valuesattr.export-no-attribute:@LibertasExportemits no attribute; a schema still carryingLibrary=trueis rejectedbitflags.catalog-values: A Bitflags integer host must be wide enough for all declared bits
Numeric semantic exclusions
Owner: schema.md#numeric-semantic-exclusions
numeric.exclusions: Numeric semantic attributes exclude each other except the pairs the exclusion table permits
Reserved Default values and constant references
Owner: schema.md#reserved-default-values-and-constant-references
defaults.reserved.null:$nullis a Default only on a Nullable field, neverFixed
User and group defaults
Owner: schema.md#user-and-group-defaults
user.default-selectors: User Default selectors are case-sensitive: a scalar takes one, a List a comma sequence; unknown tokens are errors
Fixed current-user security constraint
Owner: schema.md#fixed-current-user-security-constraint
fixed-user.current-user-only:Fixedon a User is a Hub-checked security constraint whose only valid value iscurrent-userfixed-user.placement:Fixed(current-user)needs a scalar User in a request payload outside Lists; any other use is an error
MIME-aware Bytes
Owner: schema.md#mime-aware-bytes
mime.filter-grammar:MimeTypesis a unique lowercase comma list of exact types or ranges; a field replaces its type's filter
5.3 Enumerations
Owner: schema.md#53-enumerations
types.enum.default-normalized: An EnumerationDefaultis a member name or fixed value, normalized to the member's numeric valueprotocol-variant.placement:ProtocolVariantgoes only on an ordinary Enumeration member and names one variant of each consuming protocol
5.4 Unions
Owner: schema.md#54-unions
union.tag-field-script-only:UnionTagField=trueis ScriptLanguage-only metadata, never emitted for Rustunion.discriminator: Each Union member'sDiscriminatorequals its zero-based declaration index;Fixednever identifies a member
6.3 Function data schemas
Owner: schema.md#63-function-data-schemas
data-schema.function-binding:FunctionDataSchemanames key and value Unions; external targets use FQNs and add dependencies
7. Path-based object and choice binding
Owner: schema.md#7-path-based-object-and-choice-binding
enumsource.path-and-host:EnumSourcehas one path to a same-tree List; without a key the host is an unsigned integer index
Enumsource keys
Owner: schema.md#enumsource-keys
enumsource.keyed-host: A keyed target List makes the host store the member's key; the host type equals the key'skey.placement:Keyis the markertrueon a direct Table field onlykey.type: A key field is a non-Nullable String or integer Numberkey.unique: A key field also carriesUniquekey.one-per-table: A Table has at most one key field, counting inherited fieldskey.list-member-only: A keyed Table occurs only as a List member
Enumsource list hosts
Owner: schema.md#enumsource-list-hosts
enumsource.list-host: A List EnumSource host has non-Nullable scalar elements of the key or index type
8. Types-only and interoperable packages
Owner: schema.md#8-types-only-and-interoperable-packages
types.compatible.one-declaration: A compatible type declares exactly oneForeignTypeSchema