Value kinds: strings, members, heads, unions, slot-local forms
Five More Ways to Narrow a Slot
Value kinds: shapes gave you the named-kind pattern and the refinements that work on shape: underlying kind, vector length, unit rule, numeric bound, representation tag. Those all constrain what a value is. The five in this lesson constrain what it is allowed to say:
string bounds how long the text may be, and what shape it must havemember sets a closed list of legal nameshead sets a closed list of legal form heads (and how many of each)unions several alternatives behind one slotslot-local forms forms a slot declares inline, for its own useThe reading habit does not change. Underlying shape first, then refinement, then surface value. What does change is that each axis has its own diagnostic code, so the cheat sheet at the end of this lesson is the fastest route from an error message back to the right line in the plugin docs. If you only remember one thing from here, remember that the code names the layer.
String Bounds
Atoms and intent said a string carries opaque text and nobody validates it. That was true of the language and it is not true of a schema. An id that must not be empty, an address that has to look like an address, a version that has to be a version: these are string slots where “any text” is the wrong contract, and a string bound is how a plugin says so.
A string bound applies to a string-underlying kind and constrains the value’s length, pattern, or format. Each field is optional; the validator applies them cheapest-first (length, then format, then pattern).
Example contracts:
slug: string, length 1-64, format pathemail-address: string, format emailsemver-string: string, format semverAccepted values for slug:
(post :id "intro")(post :id "release-notes-2026-05")Rejected because below :min-len:
(post :id "")Likely diagnostic: string_too_short. Other diagnostics in this
family:
string_too_long: codepoint count above:max-len.string_format_mismatch: the value fails the declared:format, one of email / uri / path / uuid / semver.string_pattern_unsupported::patternis declared but this build has no regex engine. It is a warning, and validation still succeeds.string_pattern_mismatch: reserved for the engine milestone. v1 builds never emit it.string_bounds_invalid: emitted by the loader for an empty range, a negative bound, an empty pattern, a wrong underlying kind, or a member literal that itself fails the declared length or format.
Length is measured in UTF-8 codepoints, so "héllo" (5 cp / 6 bytes)
passes :max-len 5. The parser guarantees well-formed UTF-8, so
the count is total. No normalisation is applied, so precomposed "é"
(1 cp) and decomposed "é" (2 cp) count differently.
:pattern is accept-but-warn in v1: declaring it does not yet
enforce a regex (the engine lands later), but the loader stores the
source and the validator fires string_pattern_unsupported at every
matched value site so authors know the constraint is informational.
The wire shape is stable, so once the engine lands the same manifest
starts enforcing the regex without a spec change.
Member Sets
A member set is the payoff for Atoms and intent’s
advice to write named choices as symbols. It is a closed list of
accepted values for a symbol-underlying or string-underlying kind, and
it is what turns “write ortho here” from a convention into a check.
For the shapes plugin:
fill-rule: symbol, members evenodd | nonzeroAccepted:
(circle :center [0 0] :radius 1 :fill evenodd)(circle :center [0 0] :radius 1 :fill nonzero)Rejected:
(circle :center [0 0] :radius 1 :fill diagonal)Likely diagnostic: not_member. Repair with one of the documented
symbols:
(circle :center [0 0] :radius 1 :fill evenodd)Do not repair symbol member sets with keywords:
(circle :center [0 0] :radius 1 :fill :evenodd)That runs into the keyword-pairing rule from
Forms and keyword pairing. :fill no longer receives
a value; both :fill and :evenodd are read as positional flags.
Closed enum-like values are usually symbols:
:fill evenoddIf a plugin documents a string-underlying member set, then use quoted strings instead:
blend-mode: string, members "normal" | "multiply"(layer :blend "multiply")The contract decides whether the closed values are symbols or strings.
A member set is closed and written in the plugin. Cross-references covers the other way a symbol slot gets a fixed list of legal values: read out of the document being validated, or extracted from a string inside it.
Enums whose names start with a digit
Some enums name their members with a digit first. WebGPU’s texture
dimensions are "1d", "2d", "3d"; its view dimensions add 2d-array,
cube, and cube-array. A plugin may declare those directly:
texture-dimension: symbol, members 1d | 2d | 3dview-dimension: symbol, members 1d | 2d | 2d-array | cube | cube-array | 3dAccepted:
(texture :name albedo :dimension 2d :view 2d-array)2d-array works for the reason Numbers, units, vectors
gives: inside a unit, a hyphen joins two letter runs when a letter
follows it, so the unit here is d-array and the whole thing is one
value. Without that rule this was 2d plus a stray symbol -array: one
intended value, two diagnostics.
You write the spelling the spec uses. There is no quoting and no numeric
lookup table to memorise, which is what schemas used to force, with
:view-dimension 3 ; cube and a comment carrying the meaning.
Why this needs its own heading: 2d is not a symbol.
Numbers, units, vectors showed that a digit-leading
token lexes as a number with a unit: value 2, unit d. So the
schema matches on that pair rather than on the text, and three
consequences follow:
(texture :dimension 2.0d) ; ✓ same magnitude, same unit(texture :dimension 02d) ; ✓ the leading zero is not part of the name(texture :dimension 2.5d) ; ✗ fractional, so it matches no member(texture :dimension 2b) ; ✗ the unit is part of the name(texture :dimension 2) ; ✗ no unit, so not a spelling at allThe last two fail differently, and the difference is informative.
2b is not_member, because a unit-bearing number is the right shape
here and it is simply not one of the three. 2 is wrong_underlying,
because a bare number is not a name in the first place.
Repair drill:
(texture :name albedo :dimension 4d)not_member, and the diagnostic names the set:
got `4d` (allowed: `1d`, `2d`, `3d`)so pick one of the three:
(texture :name albedo :dimension 3d)Head Sets
A member set closes the list of legal names. A head set closes the
list of legal forms: the slot value must be a nested form, and that
form’s head must be one of the listed ones.
Forms and keyword pairing’s repair for
(badge :label "ok" :shape :circle) was to write a form in the slot,
and this is the schema half of that story, the part that says which
forms.
For the shapes plugin:
shape-form: form, heads circle | rectAccepted:
(badge :label "dot" :shape (circle :center [0 0] :radius 1))
(badge :label "box" :shape (rect :origin [0 0] :size [10 10]))Rejected:
(badge :label "bad" :shape (group :name "not-a-shape"))group is a known form, but it is not a member of the allowed head set.
Likely diagnostic: not_head_member. Repair with one of the allowed
heads:
(badge :label "ok" :shape (rect :origin [0 0] :size [10 10]))A head set is different from a symbol member set:
:fill evenoddstores a symbol value and checks it againstevenodd | nonzero.:shape (circle ...)stores a form value and checks the form head againstcircle | rect.
How Many?
On a form’s :positional slot, where the head set governs a list of
children rather than one value, it can bound the count as well as the
vocabulary. Spell the heads out as (head …) children and each one may
carry :min / :max:
(value-kind :name pipeline-section :underlying form :heads (head-set (head :name vertex :min 1 :max 1) ; exactly one (head :name fragment :max 1) ; at most one, none is fine (head :name constant))) ; any number
(form :name render-pipeline :positional pipeline-section (key :name name :type symbol))Read the three spellings carefully, because the floor defaults to 0:
:min 1 :max 1: exactly one.:max 1alone: at most one. Zero is fine.- no bound: any number, including zero.
Accepted:
(render-pipeline :name main (vertex :entry vs_main) (fragment :entry fs_main) (constant :name gamma :value 2.2) (constant :name exposure :value 1.0))Too many:
(render-pipeline :name main (vertex :entry vs_main) (fragment :entry fs_main) (fragment :entry fs_alt))positional_too_many, reported on the second (fragment …), which
is the line to delete. Not on the parent, and not once per extra child: a form
four (fragment …) children over its ceiling still gets one diagnostic,
naming the real count.
Too few:
(render-pipeline :name main (fragment :entry fs_main))positional_missing, reported on (render-pipeline …) itself. You
cannot know a head is absent until the children run out, so there is no
child to point at, which is the same reason a missing required key lands on the
form’s head rather than anywhere in particular.
Three things that will save you a debugging session:
:names [a b c]cannot carry a count. The two spellings are exclusive, so adding a bound to one head means writing them all as(head …).:open truedoes not turn the counts off. Openness widens which keywords a form accepts. A positional count is a different surface, and declaring:positional <bounded-kind>opts into it.- The counts only bite on
:positional. Reuse the same kind on a(key :type pipeline-section)slot and the bounds ride along inertly: a keyed slot holds one value, so:max 1is trivially true and:min 1has no set to be missing from. That is deliberate, and it keeps a bounded kind shareable between a slot that has a population and one that does not.
How Many Altogether?
Every bound above counts one head. Some rules count the set.
A WebGPU bind-group-layout entry binds exactly one resource: a buffer, a
sampler, or a texture. Try to say that with per-head bounds and watch it
fail. Give each head :max 1 and an entry with a buffer and a sampler
is accepted, because each head is within its ceiling. Give one head :min 1 and
you have demanded a buffer specifically, which is a different rule.
The claim is about the set, so it is spelled on the set:
(value-kind :name bgl-resource :underlying form :heads (head-set :min-children 1 :max-children 1 ; exactly one, whichever (head :name buffer :max 1) ; …and not two of the same (head :name sampler :max 1) (head :name texture :max 1)))
(form :name entry :positional bgl-resource (key :name binding :type number)):min-children and :max-children count children of any head in the
set. Read the four cases:
(entry :binding 0 (buffer :type uniform))Accepted: one resource.
(entry :binding 1 (buffer :type uniform) (sampler :type filtering))positional_too_many, on the (sampler …). Both per-head ceilings are
satisfied; only :max-children 1 refuses this.
(entry :binding 2)positional_missing, on (entry …). Every per-head bound here is a
ceiling, so an empty child list satisfies all of them.
(entry :binding 3 (buffer :type uniform) (buffer :type storage))positional_too_many again, but read the message. It says at most 1 buffer positional child, not at most 1 positional child from [buffer | sampler | texture]. This document breaks both rules at once, and you
get one diagnostic: the per-head one, because it points at the line to
delete. The set’s complaint follows from it.
That is the habit to build: the message tells you which level fired. A bracketed set means the children are individually fine and there are simply too many of them together, so the repair is to pick one, not to de-duplicate.
Two more things:
- The compact spelling works here.
(head-set :names [cube sphere] :max-children 1), meaning “at most one generator”, is legal, because the aggregate needs no per-head metadata. Only per-head counts force the(head …)spelling. - The loader refuses an impossible set. Two heads at
:min 1under:max-children 1isinvalid_manifest: satisfying both needs two children and the set allows one. Note that neither head alone looks wrong on its own; the check has to add them up.
Unions
Every refinement so far narrows a slot to one shape. Sometimes a slot
genuinely takes two: a note is a pitch or an event, a dimension is a
literal or the name of a constant. A union says “this value may
satisfy any one of these alternatives”, where each alternative is
another named kind or a primitive shortcut such as number, symbol,
or form.
The validator tries alternatives in the order the plugin declared them. As an author, the main thing to notice is the failure case: if no alternative accepts the value, the diagnostic lists the alternatives as a menu of legal shapes.
Example music contract:
pitch: symbol, members E4 | G4 | A4 | B4 | _event: form, heads n | restnote-or-event: union pitch | event
(phrase ...) :notes vector<note-or-event> optionalNow every element of :notes is checked against the union:
(phrase :notes [E4 (n G4 0.5b) _ (rest 0.25b)])Read the elements:
E4satisfiespitch.(n G4 0.5b)satisfiesevent._satisfiespitch.(rest 0.25b)satisfiesevent.
This fails:
(phrase :notes [E4 X4 (n G4 0.5b)])X4 is not in the pitch member set, and it is not a form, so no
alternative accepts it. Likely diagnostic: union_no_branch_matched.
Repair with a value that fits one branch:
(phrase :notes [E4 G4 (n G4 0.5b)])The diagnostic lists the alternatives the plugin declared. Use that list as a menu of legal shapes.
Order Is Part Of The Contract
Alternatives are tried in declaration order and the first one that accepts wins. No alternative is “more specific” than another, and none is preferred by shape. Order is the whole rule.
Most of the time this is invisible, because alternatives do not overlap:
a symbol cannot satisfy vec4, a vector cannot satisfy pitch. But
when two alternatives can both accept the same value, order decides
which one, and that is usually deliberate:
byte-count: numbersize: union byte-count | symbol1024 matches byte-count. A bare name matches the symbol half. Had
the plugin listed symbol first, it would still only claim symbols, so
nothing changes here. A union of two symbol kinds is a different
story, and Cross-references
shows the case where order quietly decides which entity a name refers
to.
The practical rule for reading a schema: when two alternatives overlap, the earlier one is what you get. When you cannot tell which one accepted your value, ask the tooling: go-to-definition on the value lands in whichever declaration actually claimed it.
Form Alternative Pitfall
A union alternative named form is not a wildcard for unknown
parenthesized syntax.
Assume this contract:
vec4: vector, length 4, element numbervalue: union number | vec4 | formAssume (set ...) itself is a known form. This still fails if foo
is not declared by any loaded plugin:
(set :value (foo 1 2))Likely diagnostic: unknown_form, not union_no_branch_matched. The
slot accepts form-shaped values, but form heads still resolve against
the schema. Repair by using a form whose head the schema knows:
(set :value (+ 1 2))If a plugin truly wants to accept absolutely any value, the slot is
typed any. A union containing form means “any declared form,” not
“any parentheses.”
The scalar-or-ref Shorthand
One union shows up often enough to earn its own shorthand: “a literal
value, or a symbol that names a constant defined elsewhere.” A plugin
writes it as a scalar-or-ref kind over a base kind, and the loader
expands it to union base | symbol.
dim-value: numberdim: scalar-or-ref, base dim-valueSo dim accepts either a number or a bare symbol:
(dispatch :x 64 :y WORKGROUP_SIZE :z 1)64 and 1 take the scalar branch; WORKGROUP_SIZE is a bare symbol,
so it takes the reference branch, naming a constant the host resolves
later (the same #define-style pattern as a cross-reference, which is
the subject of the next lesson).
A quoted string is neither a number nor a symbol:
(dispatch :x "64" :y WORKGROUP_SIZE)Likely diagnostic: union_no_branch_matched. The shorthand is a union
underneath, and a string is a shape neither half could take, so it
fails exactly as a hand-written union would, naming both alternatives.
Repair by dropping the quotes for a reference, or writing a number for
a literal:
(dispatch :x 64 :y WORKGROUP_SIZE)Is the reference half checked?
Read the plugin line carefully, because two scalar-or-ref kinds that
look alike behave very differently on a typo. The reference half is
whatever the plugin named as its ref, and if it named nothing, the
answer is the plain symbol type, which accepts any spelling.
dim: scalar-or-ref, base dim-value ; ref defaults to symbolbones: scalar-or-ref, base bone-count, ref define-ref ; ref is a cross-ref kindNow misspell a constant in each:
(dispatch :y WORKGROUP_SIZ) ; A: validates clean(mesh :bones MAX_BONE) ; B: not_cross_refLine A passes. WORKGROUP_SIZ is a perfectly good symbol, and the
reference half only asked for a symbol, and nothing checked that a constant
by that name exists. The mistake surfaces later, at whatever point the
host tries to resolve it.
Line B fails at validate time, because define-ref is a cross-reference
kind and the document contains no matching (define …).
Note the diagnostic on line B: not_cross_ref, not
union_no_branch_matched. The kind is a union underneath, but its two
halves are disjoint by shape (a symbol can only have meant the reference
half, a number only the literal half), so when the value fits
neither, the validator reports the half the value’s shape selected,
with that half’s own reason. A symbol gets not_cross_ref naming the
form it had to be declared by; a number outside the base’s bounds gets
number_above_max (or number_below_min, unit_forbidden,
repr_out_of_range …) naming the bound. Only a shape neither half takes
(the quoted string above, or a vector) gets the union’s own
union_no_branch_matched with its list of alternatives.
Slot-Local Forms
A head set picks from forms that already exist somewhere. Sometimes the
form you want exists nowhere else and should not: a (dot) that only
means anything inside one slot does not belong in the global vocabulary,
where it would pollute completion lists and collide with other plugins.
So a slot may declare its own forms inline, right where it is declared. Those local forms are part of the slot’s contract, not the global vocabulary.
(canvas ...) :shape form, local circle | rect | group circle: (r number required) rect: (w number required) (h number required) group: (child form required, local dot)canvas’s :shape slot defines a local circle, rect, and group.
Resolution follows three rules.
Local first. A head that names a local form resolves to that local form:
(canvas :shape (circle :r 12))This local circle takes :r. If a global circle also exists, the
local one shadows it inside this slot, so a global circle that took
:radius is not what is checked here.
Additive fallback. A head that is not local still resolves against the global vocabulary:
(canvas :shape (line :from [0 0] :to [10 10]))line is not one of the slot’s local forms, so it falls back to the
global line. Local forms add to the global set; they do not hide it,
except where a name collides as circle does above.
Local forms nest. A local form can declare its own local slots:
(canvas :shape (group :child (dot)))The local group has a :child slot with its own local dot.
A head that matches neither a local form nor a global one is the error case:
(canvas :shape (triangle))Likely diagnostic: unknown_local_form. This is more specific than the
plain unknown_form you would get at the top level, because the slot
narrowed the choices. Repair with a head the slot accepts, either a
local form or a known global one:
(canvas :shape (circle :r 12))Two boundaries are worth remembering. A local form is invisible outside
its slot: writing (rect :w 1) at the top level is an ordinary
unknown_form, because rect exists only inside canvas’s :shape. And
a namespace-qualified head skips local resolution entirely; it goes
straight to the global vocabulary.
Head Sets and Slot-Local Forms
These two features look like they compete. They do not: they run in sequence, and reading a diagnostic correctly depends on knowing which step produced it.
Step one: is this head allowed here? The head set answers that from the head’s text alone. It compares spelling against its list and looks nothing up.
Step two: what is the body checked against? Only now does the validator go looking for a form of that name, and it looks locally first, then globally.
The consequence is worth stating plainly, because it saves you writing
forms you do not need: a head set names spellings, not declarations. If
the only storage-texture form is a local of the slot you are in, the
head set is satisfied and the body is checked against that local. You do
not need to declare a global storage-texture to “make the name
resolve.”
Now predict the diagnostics. The head set is [buffer storage-texture ghost], and there is a local form for buffer and storage-texture but
none anywhere for ghost:
(entry :binding 0 (sampler :type filtering)) ; A: head not in the set(entry :binding 0 (ghost :x 1)) ; B: head in the set, no formLine A produces two diagnostics: not_head_member from step one,
and unknown_local_form from step two. Both steps failed, so both
report.
Line B produces one: just unknown_local_form. This is the case
worth remembering, because the head set admitted ghost: ghost is
on its list, and the complaint came entirely from step two having
nothing to descend into. A head set will never tell you a name is
undeclared; that is not its job.
Diagnostic Cheat Sheet
When a value kind fails, the diagnostic usually tells you which layer of the contract you violated:
| Diagnostic | What to reread |
|---|---|
wrong_underlying | The kind’s underlying shape: number, string, symbol, vector, form. |
vector_length_mismatch | The fixed vector length (:len). |
vector_too_short / vector_too_long | The :min-len / :max-len element-count window. |
repr_out_of_range | The :repr machine type’s range, and integrality for integer types. |
unit_required | The unit requirement on a number-underlying kind. |
unit_not_allowed | The allowed unit suffix list. |
unit_forbidden | The kind rejects every unit; drop the suffix. |
not_member | The closed symbol or string member list. On a digit-leading set, also check the magnitude and the unit. |
not_head_member | The closed form head list. |
positional_too_many | A ceiling: the head’s :max, or the set’s :max-children if the message names a bracketed set. Reported on the child that crossed it. |
positional_missing | A floor: the head’s :min, or the set’s :min-children if the message names a bracketed set. Reported on the parent form’s head. |
unknown_local_form | The slot’s own local form set, plus the global vocabulary. |
union_no_branch_matched | The union alternatives. |
string_too_short / string_too_long | The :min-len / :max-len codepoint bound. |
string_format_mismatch | The named format checker (email / uri / path / uuid / semver). |
string_pattern_unsupported | The :pattern constraint is informational in this build (no regex engine). |
This is the repair loop:
- Find the form and key in the diagnostic path.
- Read that key’s declared value type in the plugin docs.
- If the key names a value kind, read the value-kind line.
- Rewrite the value to match the underlying shape first, then the refinement.
Exercises
For each exercise, read the contract first, then repair the source.
Member Set
Contract:
fill-rule: symbol, members evenodd | nonzero(circle ...) :fill fill-rule optional(circle :center [0 0] :radius 1 :fill diagonal)Repair:
(circle :center [0 0] :radius 1 :fill evenodd)Do not repair it with a keyword:
(circle :center [0 0] :radius 1 :fill :evenodd)That triggers the keyword-pairing problem from Forms and keyword pairing.
Digit-Leading Member Set
Contract:
texture-dimension: symbol, members 1d | 2d | 3d(texture ...) :dimension texture-dimension optionalPredict the diagnostic for each, then repair:
(texture :name a :dimension 4d)(texture :name b :dimension 2b)(texture :name c :dimension 2)(texture :name d :dimension 2.5d)The first, second, and fourth are not_member, because each is a unit-bearing
number, which this slot accepts as a shape; they are just not in the set.
The third is wrong_underlying: a bare number is not a spelling at all,
so it fails one layer earlier.
Repair:
(texture :name a :dimension 3d)(texture :name b :dimension 2d)(texture :name c :dimension 2d)(texture :name d :dimension 2d)Head Set
Contract:
shape-form: form, heads circle | rect(badge ...) :shape shape-form optional(badge :label "bad" :shape (group :name "not-a-shape"))Repair with an allowed head:
(badge :label "ok" :shape (rect :origin [0 0] :size [10 10]))Positional Counts
Contract:
pipeline-section: form, heads vertex (exactly 1) | fragment (at most 1) | constant (any)(render-pipeline ...) :name symbol required positional pipeline-section(render-pipeline :name main (vertex :entry vs_main) (fragment :entry fs_main) (fragment :entry fs_alt))Two (fragment …) children against :max 1. Likely diagnostic:
positional_too_many, on the second fragment, which is the extra one, not the
form. Repair by removing it:
(render-pipeline :name main (vertex :entry vs_main) (fragment :entry fs_main))Now predict this one before reading on:
(render-pipeline :name main (fragment :entry fs_main) (constant :name gamma :value 2.2))positional_missing, because vertex is :min 1 and there is none. It is
reported on (render-pipeline …) itself, because the fact “no vertex
anywhere in this list” belongs to the list, not to any child in it. Note
that constant being present helps not at all: a child counts towards a
head only if its own head matches, so nothing else can stand in for a
missing vertex. Repair by adding one:
(render-pipeline :name main (vertex :entry vs_main) (fragment :entry fs_main) (constant :name gamma :value 2.2))Union
Contract:
pitch: symbol, members E4 | G4 | A4 | B4 | _event: form, heads n | restnote-or-event: union pitch | event(phrase ...) :notes vector<note-or-event> optional(phrase :notes [E4 X4 (n G4 0.5b)])X4 is not in the pitch member set, and it is not a form, so neither
alternative accepts it. Likely diagnostic: union_no_branch_matched
naming pitch and event. Repair with a value that fits one of the
alternatives:
(phrase :notes [E4 G4 (n G4 0.5b)])Union With Form Alternative
Contract:
vec4: vector, length 4, element numbervalue: union number | vec4 | form(set ...) :value value requiredAssume (set ...) itself is a known form.
(set :value (foo 1 2))If foo isn’t a head in any loaded plugin, this fails with
unknown_form. The form alternative does not turn the slot into
“any parenthesized construct accepted.” Repair by using a form whose
head the schema knows about:
(set :value (+ 1 2))If you genuinely need a domain-specific construct here, check the
plugin’s loaded form vocabulary first, or look for a separate slot the
plugin documents as any.
scalar-or-ref
Contract:
dim-value: numberdim: scalar-or-ref, base dim-value(dispatch ...) :x dim required(dispatch :x "64")Repair with a literal, or a bare symbol that names a constant:
(dispatch :x 64)Slot-Local Form
Contract:
(canvas ...) :shape form, local circle | rect | group circle: (r number required)(canvas :shape (triangle))Repair with a head the slot accepts:
(canvas :shape (circle :r 12))Mastery Check
-
What does a member set usually mean for authoring?
-
2dis a legal member of a symbol member set, yet2dis not a symbol. How does that work? -
Why do
:dimension 2band:dimension 2fail differently againstmembers 1d | 2d | 3d? -
What does
union_no_branch_matchedtell you to reread? -
When two union alternatives can both accept the same value, which one wins?
-
When a union slot lists
formas one alternative, does that mean any parenthesized construct is accepted? -
What does a head set constrain?
-
A head declares
(head :name fragment :max 1)and a form carries four(fragment …)children. Where does the diagnostic land, and how many do you get? -
A form declares
:open trueand a bounded:positionalhead-set. Which rules still apply? -
The same bounded head-set kind is used on a
:positionalslot and on a(key :type …)slot. Where do its:min/:maxcounts apply? -
Every head in a set carries
:max 1. Which document does that fail to reject? -
Under
:min-children 1 :max-children 1over heads each:max 1, a form carries two(buffer …)children. How many diagnostics, and which? -
A
positional_too_manymessage readsat most 1 positional child from [buffer | sampler | texture], found 2. What does the bracketed set tell you? -
A slot typed
dim: scalar-or-ref, base dim-value(a number base). Which value takes the reference branch? -
A
scalar-or-refslot names norefkind, so the reference half is the plainsymboltype. The document misspells a constant asWORKGROUP_SIZ. What happens at validate time? -
The plugin instead declares the slot as
scalar-or-ref, base bone-count, ref define-ref, wheredefine-refis a cross-reference kind. The document writesMAX_BONEand no(define :name MAX_BONE ...)exists. Which diagnostic? -
A
:shapeslot defines local formscircle | rect. The document writes(canvas :shape (triangle)). What happens? -
A head set lists
ghost, but no form namedghostis declared anywhere - not locally, not globally. The document writes(ghost :x 1)in that slot. How many diagnostics? -
A head set names
storage-texture, whose only(form ...)declaration is a slot-local of the form you are inside. Does that work?