marianoguerra/tutuca/core does not have a README file

    ComponentSource

    pub(open) trait ComponentSource {
    fn describe(Self, module_ : String?, name : String) -> SchemaInfo? = _
    fn build(Self, module_ : String?, name : String, args : Map[String, Value], at~ : String) -> Value?
    }

    Where instances come from when a document is read back.

    A trait rather than a pair of closures for two reasons. A function TYPE cannot carry labelled parameters, so build's four arguments would be positional and two of them are String; and a source that can build a name it cannot describe — a foreign guest — wants to answer only one of the two, which a defaulted method gives it for free.

    Ctx

    pub(open) trait Ctx {
    fn path(Self) -> DispatchPath = _
    fn target_path(Self) -> DispatchPath = _
    fn name(Self) -> String? = _
    fn origin(Self) -> Origin = _
    fn send(Self, name : String, args : Array[Value]) -> Unit = _
    fn send_at_path(Self, path : DispatchPath, name : String, args : Array[Value]) -> Unit = _
    fn set_member_at_path(Self, path : DispatchPath, name : String, v : Value) -> Unit = _
    fn set_property_at_path(Self, path : DispatchPath, name : String, v : Value) -> Unit = _
    fn intent(Self, name : String, args : Array[Value], opts : IntentOpts) -> Unit = _
    fn intent_at_path(Self, path : DispatchPath, name : String, args : Array[Value], opts : IntentOpts) -> Unit = _
    fn forward(Self, args : Array[Value]?, opts : IntentOpts?) -> Unit = _
    fn reply(Self, value : Value) -> Unit = _
    fn send_reply(Self, name : String, args : Array[Value]) -> Unit = _
    fn lookup(Self, name : String, opts : LookupOpts) -> Value = _
    fn make(Self, name : String, args : Map[String, Value], opts : LookupOpts) -> Value? = _
    fn fail(Self, error : Value) -> Unit = _
    fn stop_propagation(Self) -> Unit = _
    fn at(Self) -> PathChanges = _
    fn walk_path(Self, callback : (Int, Value) -> Bool) -> Unit = _
    }

    What a handler can do besides transforming its leaf. Defined here so Handler can carry it without depending on the transactor; every method defaults to a no-op so tests and Path::update can run handlers without a dispatcher. The transactor implements the real thing.

    Fields

    pub(open) trait Fields {
    fn schema() -> SchemaInfo
    fn encode(Self) -> Map[String, Value]
    fn decode(Map[String, Value]) -> Self?
    }

    What a typed state struct states about itself: its declared schema and its conversion to and from the fields map the render and path layers read.

    A generic BOUND, not a trait object — schema and decode are facts about the TYPE, and Value::Obj already carries the object-safe half of the protocol (Obj). Nothing ever needs a &Fields.

    Three methods, all of them things only the author (or the generator reading the author's WIT) knows. There is no fourth: every dynamic operation OVER the result — typed reads, defaults, sizes, item lookup, method calls, field enumeration — is a free function in this package, written once rather than implemented per type.

    Obj

    pub(open) trait Obj {
    fn component_id(Self) -> Int? = _
    fn field(Self, name : String) -> Value? = _
    fn with_field(Self, name : String, v : Value) -> Value? = _
    fn property(Self, name : String) -> Value? = _
    fn set_property(Self, name : String, v : Value) -> Outcome = _
    fn member_at(Self, name : String, stack : &Stack) -> Value? = _
    fn set_member(Self, name : String, v : Value) -> Outcome = _
    fn mutate_member(Self, name : String, operation : String, args : Array[Value]) -> Outcome = _
    fn item(Self, key : PathKey) -> Value? = _
    fn with_item(Self, key : PathKey, v : Value) -> Value? = _
    fn seq_entries(Self) -> Array[(PathKey, Value)]? = _
    fn trigger(Self, name : String) -> Value? = _
    fn method_at(Self, name : String, stack : &Stack) -> Value? = _
    fn trigger_at(Self, name : String, stack : &Stack) -> Value? = _
    fn handler(Self, bucket : HandlerBucket, name : String) -> Handler? = _
    fn schema(Self) -> SchemaInfo? = _
    fn size(Self) -> Int? = _
    fn identity(Self) -> ObjId? = _
    fn eq(Self, other : &Obj) -> Bool = _
    fn debug(Self) -> String = _
    fn persist_id(Self) -> String? = _
    }

    Component-instance protocol (the port of JS's runtime Records tagged with a hidden component symbol). ONE trait serves both hybrid representations: the Value-backed Instance (component package) and user-defined typed structs. Instances live INSIDE Value so they flow through every Value-typed seam (binds, handler args, dynamic lookups, iterated seqs). Fns returned by member / trigger and the Handler returned by handler are SELF-PRE-BOUND (they close over the concrete Self — the no-downcast analogue of late-bound this) and ignore args element 0. Every method defaults to an empty/None answer.

    Stack

    pub(open) trait Stack {
    fn lookup_bare(Self, String) -> Value = _
    fn lookup_event_path(Self, Array[String]) -> Value = _
    fn lookup_bind(Self, String) -> Value = _
    fn lookup_dynamic(Self, String) -> Value = _
    fn lookup_storage(Self, String) -> Value = _
    fn lookup_member(Self, String) -> Value = _
    fn lookup_method(Self, String) -> Value = _
    fn lookup_trigger(Self, String) -> Value = _
    }

    Evaluation environment (the stack). Every method defaults to Null so implementations (and test mocks) provide only the lookups they use. lookup_method returns the RESULT of the no-arg call — the stack invokes. lookup_trigger returns Null when no render-time handler answers the name.

    BadInstant

    pub suberror BadInstant {
    BadInstant(String)
    }

    A timestamp that is not one.
    impl Show for BadInstant

    Admission

    pub(all) enum Admission {
    Admitted
    NotHere
    Refused(String)
    } derive(Eq,
    Debug
    )

    What a position answers about a form.

    Three answers rather than two, because "no" comes in two kinds and they are reported differently. A form that is simply not in this position's set is NotHere: the caller says its own bad-value sentence, naming the slot. A form the slot LANGUAGE cannot hold at any depth — a nested place, an if, a &position — is Refused, and carries the sentence that names what to write instead, because that one is about the expression rather than about where it was put.

    Builtin

    pub struct Builtin {
    name : String
    arity : Int
    apply : (Array[Value]) -> Value
    }

    One name an application may head: its arity, and what it does to already-evaluated arguments.

    The table lives in value_builtin.mbt and is reachable only through builtin / builtin_names, so a caller sees a vocabulary rather than an enum it would have to match exhaustively. apply is only ever called with exactly arity arguments — the parser refuses anything else, which is what lets the implementations index positionally.

    CtxStack

    pub(all) struct CtxStack(&Ctx)

    A &Ctx wearing a &Stack's shape, so a compute a TRANSITION calls can be handed an environment without the transition having a render stack.

    A value body takes a &Stack because it is normally called BY the render stack. A transition that calls one as a sibling is the other caller, and it holds a &Ctx instead — the same two environments, asked from a different position: Ctx::lookup walks the dispatch route (dyn the render ancestry, lex the registration scope) and answers what a *name in this component's view would answer.

    Only lookup_dynamic is implemented. Every other Stack method keeps its Null default, and that is a statement rather than an omission: a value body reads its state through s.field and its row through its own parameters, so *name is the only stack question it emits.

    pub(all), because the code that CONSTRUCTS one is generated into somebody else's package: gen weaves @tutuca.CtxStack(ctx) into a handler arm whose invariant calls a pred, and a plain pub struct is read-only outside the package that declares it — so that arm did not compile, with nothing said at generation time and a moon check error afterwards. The wrapped &Ctx is the whole representation and there is nothing to hide.
    impl Stack for CtxStack

    Dispatch

    pub(all) enum Dispatch {
    Receive(String, Array[Value])
    Intent(String, Array[Value])
    } derive(Eq,
    Debug
    )

    A dispatch: which bucket, the name, and what it carries.

    The payload-bearing twin of HandlerBucket, and it lives beside it for that reason. It was @component.Dispatch — a second enum with the same two cases — so a reader who had one and wanted the other wrote a two-arm match, and there were five of those.

    An arm matches on what the dispatch IS, never on where it came from: a view's @on name and a parent's ctx.send of that name are the same message and reach the same arm. Where it came from is Origin's question.

    Debug because a dispatch is what a failing property REPORTS. A generated message sequence that breaks a component is the counterexample, and one that cannot be printed leaves the reader with "a property failed".

    Dispatch::args

    fn Dispatch::args(self : Dispatch) -> Array[Value]

    What this dispatch carries.

    Dispatch::bucket

    fn Dispatch::bucket(self : Dispatch) -> HandlerBucket

    Which bucket answers this dispatch.

    Dispatch::name

    fn Dispatch::name(self : Dispatch) -> String

    The name this dispatch asks for.

    DispatchFrame

    pub(all) struct DispatchFrame {
    base : Path
    items : Array[DispatchStep]
    binds : Array[(Int, FrameBind)]
    } derive(Eq,
    Debug
    )

    One frame of a render path. base is the absolute transaction path where rendering resumed; items are the ordinary visual descendants rendered from there.

    binds is what the frame put in SCOPE, each paired with the number of items that came before it — so a rebuild interleaves the two in the order the renderer entered them, without the binds having to pretend to be steps to keep their place.

    DispatchPath

    pub(all) struct DispatchPath {
    frames : Array[DispatchFrame]
    } derive(Eq,
    Debug
    )

    A render path as a stack of continuations. Normal rendering extends the top frame. Rendering a located binding pushes a new frame. Bubbling removes top-frame steps, then pops the frame to return to the visual caller.

    DispatchPath::can_pop

    fn DispatchPath::can_pop(self : DispatchPath) -> Bool

    DispatchPath::compact

    fn DispatchPath::compact(self : DispatchPath) -> DispatchPath

    The addressing projection: every step in its abstract form.

    It no longer DROPS anything — every step addresses something now — so what is left is EachRenderItStep abstracting to a plain SeqStep.

    DispatchPath::concat

    fn DispatchPath::concat(self : DispatchPath, steps : Array[Step]) -> DispatchPath

    DispatchPath::is_root

    fn DispatchPath::is_root(self : DispatchPath) -> Bool

    DispatchPath::new

    DispatchPath::of_steps

    fn DispatchPath::of_steps(steps : Array[Step]) -> DispatchPath

    DispatchPath::pop_step

    fn DispatchPath::pop_step(self : DispatchPath) -> DispatchPath

    DispatchPath::push_bind

    fn DispatchPath::push_bind(self : DispatchPath, bind : FrameBind) -> DispatchPath

    DispatchPath::push_frame

    fn DispatchPath::push_frame(self : DispatchPath, path : Path) -> DispatchPath

    DispatchPath::push_item

    fn DispatchPath::push_item(self : DispatchPath, item : DispatchStep) -> DispatchPath

    DispatchPath::to_transaction_path

    fn DispatchPath::to_transaction_path(self : DispatchPath) -> Path

    DispatchStep

    pub(all) enum DispatchStep {
    Plain(step~ : Step, origin~ : Int?)
    } derive(Eq,
    Debug
    )

    One ordinary hop inside a render-path frame. origin is the component id that contributed it.

    Domain

    pub(all) enum Domain {
    DIndexOf(field~ : String, allow_none~ : Bool)
    DKeyOf(field~ : String)
    DMemberOf(field~ : String)
    DCompare(op~ : DomainOp, rhs~ : DomainOperand)
    DBetween(lo~ : DomainOperand, hi~ : DomainOperand)
    DOneOf(Array[Value])
    DElementOf(field~ : String)
    DLen(Domain)
    DNonEmpty
    DSubsetOf(field~ : String)
    DPattern(String)
    DFormat(String)
    } derive(Eq,
    Debug
    )

    What a field's declared domain is.

    The vocabulary is CLOSED, and the reason is what the whole feature is for: every arm can be read backwards as well as forwards. Forwards it rejects a value; backwards it produces one, which is what lets a generator draw states a component could actually reach instead of filtering for them. A relation that can only be read forwards is a pred — that is the line, and it is drawn at the declaration rather than here.

    Domain::applies_to

    fn Domain::applies_to(self : Domain, ty : Ty) -> Bool

    Whether this domain says anything about a value of type ty.

    ONE gate, where there were two that mirrored each other: the JSON Schema emitter decided what to DROP and the bundle loader decided what to say was dropped, and a rule stated twice is a rule that disagrees — those two already differed over TyCompProtocols.

    A bound the type cannot carry is not merely unused. minimum on a "type": "string" is a keyword a JSON Schema reader will not apply, and a reader that does not know that — an agent generating arguments, most of all — is being told something false. So the emitter drops it and the loader says so, from this one answer.

    The RELATIONAL domains — an index, a key, a member, a subset, an element — are not gated: what they read is another field, and whether that reading makes sense is a fact about the pair rather than about this type.

    Domain::to_mbt_source

    fn Domain::to_mbt_source(self : Domain) -> String

    The MoonBit source of the expression that rebuilds this domain.

    What gen splices into a generated SchemaInfo, and the twin of Domain::to_json for the reader that has a compiler rather than a parser. It is a method on the domain rather than a table in the generator, for the reason Ty::to_mbt_source is one: the source form and the value form cannot describe different domains if one of them IS the domain.

    The constructors are written UNQUALIFIED, and have to be: an enum constructor does not resolve through the pub using re-export that keeps @component.Domain spelling correct, nor through the module-root facade the playground compiles examples against. Bare works in both, because the only position the generator writes one into already knows the type.

    DomainOp

    pub(all) enum DomainOp {
    DGe
    DGt
    DLe
    DLt
    } derive(Eq,
    Debug
    )

    How a where compares. The runtime twin of @statedef.CmpOp.

    DomainOperand

    pub(all) enum DomainOperand {
    DLit(Double)
    DField(String)
    } derive(Eq,
    Debug
    )

    A comparison's right-hand side: a literal, or another field of this state.

    Expr

    pub(all) enum Expr {
    ELit(lit~ : Lit, from_macro~ : Bool, span~ : Span)
    ETpl(parts~ : Array[TplPart], span~ : Span)
    ERead(place~ : Place, span~ : Span)
    EMethod(name~ : String, span~ : Span)
    EDyn(name~ : String, span~ : Span)
    EMacroVar(name~ : String, span~ : Span)
    EConfigVar(name~ : String, span~ : Span)
    EName(name~ : String, span~ : Span)
    ETypeName(name~ : String, span~ : Span)
    EApp(name~ : String, args~ : Array[Expr], span~ : Span)
    EChain(family~ : OpFamily, ops~ : Array[String], operands~ : Array[Expr], span~ : Span)
    EUnary(op~ : UnOp, operand~ : Expr, span~ : Span)
    EIf(cond~ : Expr, then_~ : Expr, else_~ : Expr, span~ : Span)
    ERef(place~ : Place, span~ : Span)
    EEventPath(segments~ : Array[String], span~ : Span)
    }

    An expression.

    One type, because a slot's value and a block's expression are one language: @show=".open" and requires .open mean the same thing, and a second type would be a second answer about what they mean.
    impl Eq for Expr
    impl Show for Expr
    impl Debug for Expr

    Expr::admitted_in

    fn Expr::admitted_in(self : Expr, pos : Position) -> Admission

    May this form stand in this position?

    Total over the AST, and the same answer whether the caller reached the expression through a single token or through the whole grammar — which is the property the two-table version did not have.

    Expr::app

    fn Expr::app(name : String, args : Array[Expr], span? : Span) -> Expr

    A name applied to arguments.

    Expr::as_bind

    fn Expr::as_bind(self : Expr) -> String?

    The binding this expression reads whole, when it reads one.

    Expr::as_bind_member

    fn Expr::as_bind_member(self : Expr) -> (String, String)?

    The (binding, member) this expression reads, when it reads one level into a binding.

    Expr::as_field

    fn Expr::as_field(self : Expr) -> String?

    The field this expression reads, when it reads exactly one.

    Expr::as_lit

    fn Expr::as_lit(self : Expr) -> Lit?

    The literal this expression is, when it is one.

    Expr::as_seq_access

    fn Expr::as_seq_access(self : Expr) -> (String, String)?

    The (sequence, key) fields this expression reads, when it is a field-indexed-by-field read.

    Expr::bind

    fn Expr::bind(name : String, span? : Span) -> Expr

    @name — a read of a render binding.

    Expr::bind_member

    fn Expr::bind_member(name : String, prop : String, span? : Span) -> Expr

    @name.member — one level into a render binding.

    Expr::dyn_

    fn Expr::dyn_(name : String, span? : Span) -> Expr

    *name — a dynamic binding.

    Expr::eval

    fn Expr::eval(self : Expr, stack : &Stack) -> Value

    Expr::eval_as_handler

    fn Expr::eval_as_handler(self : Expr, stack : &Stack) -> Value

    Evaluate in a HANDLER position: @on's name, and the three render-time directives' (@when, @enrich-with, @loop-with).

    A separate entry rather than a case on the value, which is what the retired HandlerNamespace was: the same bare name means "a parameter" in a body and "the thing to run" here, and which one it means is a fact about the position it was written in. So the position asks, and the name carries nothing.

    Expr::event_path

    fn Expr::event_path(segments : Array[String], span? : Span) -> Expr

    e.value — a rooted path into the DOM event being handled.

    Expr::field

    fn Expr::field(name : String, span? : Span) -> Expr

    .name — a read of one of this component's own fields.

    Expr::is_literal

    fn Expr::is_literal(self : Expr) -> Bool

    Expr::lit

    fn Expr::lit(lit : Lit, from_macro? : Bool, span? : Span) -> Expr

    A literal.

    Expr::method_

    fn Expr::method_(name : String, span? : Span) -> Expr

    $name — a declared compute or pred, answered by the render stack.

    Expr::name

    fn Expr::name(name : String, span? : Span) -> Expr

    A bare name, in the position where it is a value rather than a handler.

    Expr::seq_access

    fn Expr::seq_access(seq : String, key : String, span? : Span) -> Expr

    .seq[.key] — an entry of one of this component's sequences, indexed by another of its fields.

    The one indexed shape a slot can spell: both halves are plain fields, which is what makes it addressable as a SeqAccessStep without evaluating anything.

    Expr::span

    fn Expr::span(self : Expr) -> Span

    Where this expression was read from.

    Expr::to_path_item

    fn Expr::to_path_item(self : Expr) -> Step?

    Expr::to_source

    fn Expr::to_source(self : Expr) -> String

    Print an expression back as canonical source. Round-tripping through this is how the grammar is pinned: parse, print, parse again, and the two ASTs agree.

    Expr::tpl

    fn Expr::tpl(parts : Array[TplPart], span? : Span) -> Expr

    $'…' — a string template.

    Expr::type_name

    fn Expr::type_name(name : String, span? : Span) -> Expr

    A bare Uppercase name — a component type.

    FieldDomain

    pub(all) struct FieldDomain {
    field : String
    domain : Domain
    } derive(Eq,
    Debug
    )

    One field's domain, as the schema carries it.

    A flat list of pairs and not a map, because several clauses may name one field and they CONJOIN: where n >= 0 beside where n <= 100 is one field with two entries, and a map would have made the second silently replace the first.

    FieldInfo

    pub(all) struct FieldInfo {
    name : String
    ty : Ty
    }

    One declared field of a component's state.

    Two parts, where there were six. The WIT spelling, the runtime kind, a collection's element type, a slot's component and a closed set's members are all FUNCTIONS of the type (ty_info.mbt), so they are asked rather than stored — which is what stops them from contradicting each other, and what lets a reader descend into list<card> instead of receiving the string "card" and having nowhere to take it.

    FieldInfo::default

    fn FieldInfo::default(self : FieldInfo) -> Value

    FieldInfo::kind

    fn FieldInfo::kind(self : FieldInfo) -> FieldKind

    The runtime kind this field carries — a projection of its type, never a second statement about it.

    FieldInfo::new

    fn FieldInfo::new(name : String, ty : Ty) -> FieldInfo

    FieldKind

    pub(all) enum FieldKind {
    FBool
    FText
    FInt
    FFloat
    FList
    FMap
    FAny
    FComp(comp~ : String, args~ : Map[String, Value])
    FSet
    FOMap
    } derive(
    Debug
    )

    What a field carries at runtime. DECLARED, never inferred.

    FComp fields hold a child component instance created through the registration scope; FSet/FOMap are the Map-backed set / ordered-map refinements.

    FnSource

    pub struct FnSource {
    // private fields
    }

    A ComponentSource out of plain functions, for a caller with no type to hang them on — a test, a one-off, a page that resolves two ways.

    FnSource::new

    fn FnSource::new(build : (String?, String, Map[String, Value], String) -> Value?, describe? : (String?, String) -> SchemaInfo?) -> FnSource

    FrameBind

    pub(all) enum FrameBind {
    Scope(val~ : Expr)
    Each(val~ : Expr, when_val~ : Expr?, enrich_with_val~ : Expr?, loop_with_val~ : Expr?, key~ : PathKey)
    } derive(Eq,
    Debug
    )

    A binding a render frame introduced, replayed when the frame is rebuilt.

    Not a step, because it addresses nothing: it says what the rebuilt stack should have IN SCOPE at a point along the path, which is a different question from where a value lives. Both cases are computed LAZILY at rebuild time — they carry the expressions the renderer evaluated rather than the values it got, so a rebuild sees the state as it is now and the renderer's own answer is never stale.

    Handler

    pub(all) struct Handler((Array[Value], &Ctx) -> Value?)

    A leaf-update handler, resolved ON the leaf so self is pre-bound (the original bound this at call time; binding at resolution time is equivalent — same instance either way). Receives its args and the dispatch Ctx (appended as the last handler argument). Returns the new leaf, or None for "no change" (the analogue of the newLeaf !== curLeaf identity check — answering None lets the traversal skip the spine rebuild without comparing anything).

    HandlerBucket

    pub(all) enum HandlerBucket {
    Receive
    Intent
    } derive(Eq,
    Debug
    )

    Dispatch buckets a handler can live in (semantics.md §6). Alter is render-time only and never dispatched, so it is not a bucket here.

    TWO of these, and one question separates them: does the sender know who handles this? Receive holds every ADDRESSED message whoever sent it — a view, a parent, the host, or an answer to an intent; Intent holds every ROUTED one, dispatched by somebody who named a job rather than a target.

    A view's name is addressed at the component the view belongs to, which is what send means, so there is no separate bucket for one.

    HandlerBucket::label

    fn HandlerBucket::label(self : HandlerBucket) -> String

    The bucket as the wire/display word.

    HandlerBucket::ordinal

    fn HandlerBucket::ordinal(self : HandlerBucket) -> Int

    The bucket's case index on the WIRE.

    A numbering, not a vocabulary: the host's buckets and the guest's are the same two, so there is nothing to translate — what this pins is the ORDER, which is the WIT variant's case order and cannot be changed without changing the contract. It lives here, beside the enum, so the two numbers have exactly one owner: a second copy anywhere is a second contract.

    IntentAnswer

    pub(all) enum IntentAnswer {
    Ok(Value)
    Failed(Value)
    Pass
    } derive(Eq,
    Debug
    )

    What a static intent handler answers.

    Pass is the case a walk needs: a handler that has nothing to say declines, and the walk goes on to the next one — the same freedom a component's update arm has when it answers Unhandled. Without it, a handler with nothing to contribute could only invent an error.

    IntentCall

    pub(all) struct IntentCall {
    name : String
    args : Array[Value]
    from : DispatchPath
    } derive(Eq,
    Debug
    )

    What a static intent handler is handed.

    from is the sender's position. A host reads it to decide whether the sender may ask — which is what tgc/SECURITY.md §7 says it cannot do today — and the walk needs it anyway to route the answer, so the handler gets it for free.

    This lives in core rather than beside Dispatch in component for a mechanical reason: transactor constructs one and component consumes one, and neither imports the other. It is pure data over core's own types, so this is the only place both can see it.

    IntentFn

    pub(all) struct IntentFn((IntentCall, (IntentAnswer) -> Unit) -> Unit)

    An intent handler registered in a scope.

    It receives an IntentCall — carrying from, the sender's position, which is what lets a host decide whether this sender may ask — and it may answer Pass. Pass DECLINES: a handler with nothing to say hands the intent to its parent scope instead of inventing an error to satisfy an obligation to answer. That is the whole of why lookup_intent is a walk rather than a lookup — declining only means something if there is somewhere left to go.

    ONE of these, in core, where there were two: @component.IntentFn and @tutuca.IntentFn, identical to the field, with an adapter in app that unwrapped one and rewrapped it as the other. Neither package may depend on the other, which is exactly the case core exists for.

    IntentOpts

    pub(all) struct IntentOpts {
    route : Array[Leg]
    on_ok_name : String?
    on_failed_name : String?
    on_unhandled_name : String?
    live_path : Bool
    } derive(Eq,
    Debug
    )

    Options for Ctx::intent.

    route is the walk itself. The three answer names are the three ways a walk can end, and each carries its own payload: a hop replied, a hop failed, or the route ran out with nobody answering — which is not the same answer as a handler failing. live_path opts out of pinning field-resolved keys at dispatch time.

    The middle one is Failed and not Error because that is what happened: a handler ran and did not succeed. An Error is a thing, and the arm reads as if one were being handed over; <n>Failed says the outcome, which is what the other two names say.

    There is deliberately no combined result-or-error arm. An outcome a handler has to discriminate is one it can discriminate wrongly.

    IntentOpts::new

    fn IntentOpts::new(route? : Array[Leg], on_ok_name? : String, on_failed_name? : String, on_unhandled_name? : String, live_path? : Bool) -> IntentOpts

    route defaults to default_route() — the one place dyn lex is written.

    Leg

    pub(all) enum Leg {
    Dyn
    Lex
    } derive(Eq,
    Debug
    )

    A leg of an intent's route.

    Dyn walks the dynamic scope — the dispatch path, from the sender's PARENT up to the root, one pop_step() per hop — and its handlers are component instances with state. Lex walks the lexical scope — the registration chain — and its handlers are static functions with none. A route is a list of these, in the order written, and [Dyn, Lex] when nothing says otherwise.

    Leg::word

    fn Leg::word(self : Leg) -> String

    The leg word a route is written with, so a route has one spelling and not one per package that prints it.

    Lit

    pub(all) enum Lit {
    LNull
    LBool(Bool)
    LNum(Double)
    LStr(String)
    } derive(Eq,
    Debug
    )

    Literal constant payload (string | number | boolean | null)

    LookupOpts

    pub(all) struct LookupOpts {
    route : Array[Leg]
    } derive(Eq,
    Debug
    )

    Options for a name lookup: the same legs, the same array-is-walk-order contract and the same default an intent's route has.

    A separate struct from IntentOpts because the three answer names and live_path are about a walk that DISPATCHES, and a lookup does not — it asks a question and gets an answer in the same breath.

    LookupOpts::new

    fn LookupOpts::new(route? : Array[Leg]) -> LookupOpts

    route defaults to default_route(), the same one an intent takes.

    NullCtx

    pub(all) struct NullCtx {
    }

    A Ctx that dispatches nothing (the eval(null) analogue for handlers).
    impl Ctx for NullCtx

    NullStack

    pub(all) struct NullStack {
    }

    Stand-in for eval(null) on values that touch no stack
    impl Stack for NullStack

    ObjId

    pub(all) struct ObjId {
    origin : UInt64
    rev : Int
    } derive(Eq,
    Debug
    )

    A render-cache bucket for one instance: a structural fingerprint fixed when the instance was created, and a revision bumped by each successor.

    NOT an identity, and deliberately not unique. Two unrelated instances can land on the same pair — two bundles loaded at runtime declaring the same component, or two structurally equal siblings of one — and that is fine: a bucket collision costs a MISS, never a wrong subtree, because the cache validates its stored value by physical identity before returning it.

    Giving up on uniqueness is what removes the need for a process-global counter, and with it the question of how two independently loaded components avoid clashing: they do not have to.

    ObjId::next

    fn ObjId::next(self : ObjId) -> ObjId

    ObjId::of

    fn ObjId::of(fingerprint : String, fields : Map[String, Value]) -> ObjId

    ObjId::to_hex

    fn ObjId::to_hex(self : ObjId) -> String

    OpFamily

    pub(all) enum OpFamily {
    FLogic
    FCompare
    FImplies
    FAdd
    FMul
    } derive(Eq,
    Debug
    )

    The four operator families. Mixing families in one unparenthesized chain is a parse error, and the message names the parentheses to add — so a and b and c and a + b - c chain freely, a + b * c is refused, and there is no precedence to get wrong.

    Origin

    pub(all) enum Origin {
    Host
    View
    Handler
    } derive(Eq,
    Debug
    )

    Who raised a dispatch.

    Three, and the third is the one that matters: a Handler dispatch is a CONSEQUENCE — some handler already running pushed it — where Host and View are the two ways a dispatch enters the tree from outside it. That is the distinction is_external names, and a recorder needs exactly it: an external dispatch is the input a replay has to feed, a derived one is what a replay produces again for free.

    There used to be a fourth, Diagnostic, and it existed only to say that a stress run was allowed to reach the generated mutator behind a name. There is no such fallback any more (a write is a write), so there is nothing left for the case to gate.

    Origin::is_external

    fn Origin::is_external(self : Origin) -> Bool

    Did this dispatch enter the tree from outside it?

    Host and View both did — one from a host call, one from a person clicking — and neither is reproducible by re-running what came before.

    Origin::label

    fn Origin::label(self : Origin) -> String

    The origin as the wire/display word.

    Outcome

    #alias(PropertyWrite)
    pub(all) enum Outcome {
    Missing
    Unchanged
    Refused(Refusal)
    Changed(Value)
    }

    What a write to a member ANSWERED.

    Four answers because a write has four, and they are the same four every other refusing seam in the system names: nothing claimed it, a rule refused it, nothing changed, here is the successor.

    It was PropertyWrite, whose PRefused carried nothing — the refusal travelled separately through the recorder, so a caller holding one had to go and look somewhere else for the reason. Refused carries it.

    PropertyWrite is the older name and still reads for one release. The P-prefixed case names could not survive it: MoonBit has no alias for a constructor, and PRefused changed shape anyway.

    Path

    pub(all) struct Path {
    steps : Array[Step]
    } derive(Eq,
    Debug
    )

    An address into the component/state tree: a sequence of steps root→leaf.
    impl Show for Path

    Path::concat

    fn Path::concat(self : Path, steps : Array[Step]) -> Path

    Path::field

    fn Path::field(self : Path, name : String) -> Path

    Path::new().field("rows").index("rows", 2) — the absolute twin of the relative PathChanges builder, which delegates to these so the two spell a step the same way. Each returns a fresh Path, so a base is reusable.

    Path::index

    fn Path::index(self : Path, name : String, i : Int) -> Path

    A positional item of a sequence FIELD. There is no bare-index step: a Path addresses field-then-key, so a nested .a[0][1] is not expressible and the value-level item/index are what read one.

    Path::key

    fn Path::key(self : Path, name : String, k : String) -> Path

    A keyed item of a sequence field.

    Path::lookup

    fn Path::lookup(self : Path, root : Value) -> Value?

    Path::new

    fn Path::new(steps? : Array[Step]) -> Path

    Path::pin_keys

    fn Path::pin_keys(self : Path, root : Value) -> Path

    Path::pop_step

    fn Path::pop_step(self : Path) -> Path

    Path::resolve_chain

    fn Path::resolve_chain(self : Path, root : Value) -> Array[Value]

    Path::set_value

    fn Path::set_value(self : Path, root : Value, v : Value) -> Value

    Path::to_keys

    fn Path::to_keys(self : Path) -> Array[StepKey]

    Path::to_label

    fn Path::to_label(self : Path) -> String

    The addressing steps as readable text.

    Over to_keys, so the frame-only steps (which address nothing) are absent and a seq-access step shows as its field.

    Path::update

    fn Path::update(self : Path, root : Value, bucket : HandlerBucket, name : String, args : Array[Value]) -> Value

    PathChanges

    pub struct PathChanges {
    ctx : &Ctx
    steps : Array[Step]
    }

    PathChanges::build_path

    fn PathChanges::build_path(self : PathChanges) -> DispatchPath

    The absolute dispatch path this builder addresses: the ctx's path with the accumulated steps appended.

    PathChanges::field

    fn PathChanges::field(self : PathChanges, name : String) -> PathChanges

    Descend into field name.

    PathChanges::index

    fn PathChanges::index(self : PathChanges, name : String, i : Int) -> PathChanges

    Descend into element i of sequence field name.

    PathChanges::intent

    fn PathChanges::intent(self : PathChanges, name : String, args : Array[Value], opts? : IntentOpts) -> Unit

    Dispatch an intent from the built path — the routed twin of send. One method, and the route says which scope answers.

    PathChanges::key

    fn PathChanges::key(self : PathChanges, name : String, key : String) -> PathChanges

    Descend into keyed element key of map field name.

    PathChanges::send

    fn PathChanges::send(self : PathChanges, name : String, args : Array[Value]) -> Unit

    Send name at the built path.

    PathChanges::set

    fn PathChanges::set(self : PathChanges, name : String, v : Value) -> Unit

    Write name at the built path.

    The twin of send, and the distinction between them is the one the generated-mutator fallback used to blur: a dispatch ASKS a component to decide something, and a write says what a member is now. A view spells the second .field = v; this is the same door for a caller holding a ctx.

    PathChanges::set_property

    fn PathChanges::set_property(self : PathChanges, name : String, v : Value) -> Unit

    Write a PUBLIC property at the built path — the door a HOLDER gets.

    set above is the private-capable one, for a caller writing something it owns. This is for writing into a CHILD: a separate instance, often from a different bundle, whose private fields are not a holder's to touch. What it declares writable is what a holder may write.

    PathKey

    pub(all) enum PathKey {
    KInt(Int)
    KStr(String)
    } derive(Eq,
    Debug
    )

    A concrete sequence key: list index or map key (int|string)

    PathKey::from_json

    fn PathKey::from_json(j : Json) -> PathKey?

    A key back. None for anything that is neither a number nor a string — which for a key is not a recoverable shape, so the caller decides what a missing key means rather than being handed a wrong one.

    PathKey::to_json

    fn PathKey::to_json(self : PathKey) -> Json

    A key as JSON. An Int and a String are already distinguishable in JSON, so there is no tag: the reader takes a number as KInt and a string as KStr and cannot be wrong about which it had.

    PathKey::to_label

    fn PathKey::to_label(self : PathKey) -> String

    A key as its addressing text: 2 or title.

    PathKey::to_value

    fn PathKey::to_value(self : PathKey) -> Value

    A key as a Value — what @key binds to inside a loop, and what a seq-access read compares against.

    PathStep

    pub(all) enum PathStep {
    PField(String)
    PIndex(Expr)
    }

    A step below the root.
    impl Eq for PathStep

    Place

    pub(all) struct Place {
    root : PlaceRoot
    steps : Array[PathStep]
    span : Span
    }

    A PLACE: a position, not a value.

    .a.b and .a[k].b are the two things a view slot cannot spell — nested reads and nested WRITES. A slot's name lookup stays one level because nothing checks it; a body is checked code and the generator knows every type along the path.
    impl Eq for Place

    Place::to_source

    fn Place::to_source(self : Place) -> String

    A place as source: the root's sigil, then every step attached.

    PlaceRoot

    pub(all) enum PlaceRoot {
    PState(String)
    PBind(String)
    PTarget
    PParam(String)
    } derive(Eq,
    Debug
    )

    What a place is rooted at.

    Position

    pub(all) enum Position {
    PosCondition
    PosText
    PosComponent
    PosSequence
    PosProvide
    PosField
    PosEventArg
    PosEvent
    PosTrigger
    PosMacroAttr
    PosBody
    } derive(Eq,
    Debug
    )

    A position an expression can be written in.

    One case per slot the view language has, plus the block body. They are not a hierarchy and they are not orderable: @each admits a dynamic and a field and nothing else, an @on argument admits an event read that no other position may hold, and provide admits exactly the two shapes that can be ADDRESSED because a provide doubles as a resume target.

    PropertyInfo

    pub(all) struct PropertyInfo {
    name : String
    ty : Ty
    public_ : Bool
    writable : Bool
    } derive(Eq,
    Debug
    )

    One abstract property of a component.

    A property is an operation, not a promise about storage. writable says whether callers may request its synchronous, pure transition; it does not imply that a field with the same name exists.

    ProtocolBindingInfo

    pub(all) struct ProtocolBindingInfo {
    protocol_id : String
    member_name : String
    source : String
    } derive(Eq,
    Debug
    )

    A component's explicit provider for one protocol operation.

    ProtocolConformance

    pub(all) enum ProtocolConformance {
    Verified
    Deferred(Array[String])
    Invalid(Array[String])
    } derive(Eq,
    Debug
    )

    The result of checking one runtime schema against a protocol assumption.

    ProtocolInfo

    pub(all) struct ProtocolInfo {
    id : String
    handle_messages : Array[String]
    handle_intents : Array[String]
    express_messages : Array[String]
    express_intents : Array[String]
    properties : Array[PropertyInfo]
    views : Array[String]
    provides : Array[(String, Ty)]
    lookups : Array[(String, Ty)]
    } derive(Eq,
    Debug
    )

    Runtime projection of a protocol surface. All names are wire names and the id is canonical; source aliases never cross this boundary.

    ProtocolIssueCode

    pub(all) enum ProtocolIssueCode {
    ProtocolUnresolved
    ProtocolDefinitionConflict
    ProtocolNotImplemented
    ProtocolMemberMissing
    ProtocolMemberType
    ProtocolTargetMismatch
    ProtocolPropertyMissing
    ProtocolPropertyType
    ProtocolViewMissing
    ProtocolProvideMissing
    ProtocolLookupMissing
    ProtocolResultType
    ProtocolExpressionUndeclared
    } derive(Eq,
    Debug
    )

    One vocabulary shared with the static protocol validator.

    ProtocolIssueCode::word

    fn ProtocolIssueCode::word(self : ProtocolIssueCode) -> String

    Refusal

    pub(all) struct Refusal {
    code : RefusalCode
    asked : String
    rule : String
    sentence : String
    state : Value
    path : Path
    } derive(Eq,
    Debug
    )

    One refusal: where it happened, what was asked for, which rule said no, the sentence that rule produced, and the state that was rejected.

    Refusal::to_json

    fn Refusal::to_json(self : Refusal) -> Json

    One refusal as JSON — a record a host posts across a boundary, a scene report keeps, or an execution trace carries.

    to_line is the sentence a person reads in a test failure and throws away everything a machine would filter on: the code is folded into prose, the path is a Repr of its steps, and the rejected state — the thing the record exists to carry — never appears at all. This is the same record with nothing dropped.

    path is the readable label and pathKeys the structure, the same pair ObserveRecord::to_json writes, so a consumer that shows one and filters on the other reads both the same way. state is absent — not null — when the producer had none in hand, which is the distinction a Null state would erase.

    Refusal::to_line

    fn Refusal::to_line(self : Refusal) -> String

    A one-line rendering, for a host that wants text rather than the record.

    The sentence the author wrote comes LAST and unquoted, because it is the half a reader is meant to read: everything before it is provenance.

    RefusalCode

    pub(all) enum RefusalCode {
    PathUnresolved
    NoHandler
    Precondition
    Postcondition
    Invariant
    IntentDepth
    TypeNotFound
    OutOfRange
    NoSender
    BadPayload
    } derive(Eq,
    Debug
    )

    Why a dispatch produced nothing.

    Each case names a producer that exists in this repo. The design this comes from has a longer vocabulary — NO_REQUEST_FN, DECODE_FAILED, COERCED_TO_DEFAULT, OUT_OF_RANGE, TELEPORT_MISSING — and none of those is here, because a code nothing raises is a promise the runtime does not keep: a host filtering on it would conclude the failure never happens. A new case arrives with the site that raises it, in the same change.

    (@emit_mbt.Refusal is a compile-time namesake and unrelated: that one is a declaration the MoonBit backend will not compile, and it is answered to the generator rather than to a running page.)

    RefusalCode::word

    fn RefusalCode::word(self : RefusalCode) -> String

    The screaming-snake spelling — the one an author reads in a test failure.

    One vocabulary learned once: a build-time hint about a missing arm and the runtime record for the same failure say the same word.

    RuntimeNotice

    pub(all) enum RuntimeNotice {
    Refused(Refusal)
    ProtocolMismatch(RuntimeProtocolNotice)
    RuntimeWarning(String)
    } derive(Eq,
    Debug
    )

    The single centralized runtime diagnostics channel.

    RuntimeProtocolNotice

    pub(all) struct RuntimeProtocolNotice {
    code : ProtocolIssueCode
    protocol_id : String
    member_name : String
    operation : String
    detail : String
    component : String
    path : Path
    state : Value
    resolution : RuntimeResolution
    } derive(Eq,
    Debug
    )

    RuntimeResolution

    pub(all) enum RuntimeResolution {
    KeptPreviousState
    ReturnedNull
    ReturnedDefault
    EvaluatedFalse
    UsedMainView
    RenderedPlaceholder
    ContinuedIntentRoute
    DeliveredUnhandled
    DroppedMessage
    SkippedProvider
    RejectedComponentValue
    } derive(Eq,
    Debug
    )

    The graceful fallback the runtime chose after a protocol assumption failed.

    SchemaInfo

    pub(all) struct SchemaInfo {
    name : String
    fingerprint : String
    fields : Array[FieldInfo]
    properties : Array[PropertyInfo]
    view_handlers : Array[String]
    receives : Array[String]
    intents : Array[String]
    express_messages : Array[String]
    express_intents : Array[String]
    methods : Array[String]
    invariants : Array[String]
    domains : Array[FieldDomain]
    ids : Array[String]
    view_names : Array[String]
    init_names : Array[String]
    protocols : Array[ProtocolInfo]
    implements : Array[String]
    property_bindings : Array[ProtocolBindingInfo]
    view_bindings : Array[ProtocolBindingInfo]
    provide_bindings : Array[ProtocolBindingInfo]
    lookup_bindings : Array[ProtocolBindingInfo]
    }

    What a component declares, as static metadata.

    inputs is the one that matters most: the names update answers are UNKNOWABLE at runtime (it is one opaque pattern match), so introspection could only ever report THAT an update exists. The generator knows them.

    SchemaInfo::conforms

    fn SchemaInfo::conforms(self : SchemaInfo, protocol : ProtocolInfo) -> ProtocolConformance

    SchemaInfo::field

    fn SchemaInfo::field(self : SchemaInfo, name : String) -> FieldInfo?

    Linear over fields, which is the right shape at these sizes: a component has a handful of them and the array preserves declaration order, which the callers below read as much as they read the entries themselves.

    SchemaInfo::field_names

    fn SchemaInfo::field_names(self : SchemaInfo) -> Array[String]

    SchemaInfo::new

    fn SchemaInfo::new(name? : String, fingerprint~ : String, fields? : Array[FieldInfo], properties? : Array[PropertyInfo], view_handlers? : Array[String], receives? : Array[String], intents? : Array[String], express_messages? : Array[String], express_intents? : Array[String], methods? : Array[String], invariants? : Array[String], domains? : Array[FieldDomain], ids? : Array[String], view_names? : Array[String], init_names? : Array[String], protocols? : Array[ProtocolInfo], implements? : Array[String], property_bindings? : Array[ProtocolBindingInfo], view_bindings? : Array[ProtocolBindingInfo], provide_bindings? : Array[ProtocolBindingInfo], lookup_bindings? : Array[ProtocolBindingInfo]) -> SchemaInfo

    SchemaInfo::shape_fingerprint

    fn SchemaInfo::shape_fingerprint(self : SchemaInfo) -> String

    A structural fingerprint of a schema that arrives at RUNTIME, for a caller with no generated one to carry: the dynamic-component host, which receives a guest's declared shape over the module boundary and needs the same thing <v>_schema_fingerprint gives a compiled component — a value that changes when the shape does, and not otherwise (it seeds the render cache's bucket, and says when stored state can no longer be read back).

    The twin of @statedef.fingerprint, which hashes the same shape one step earlier — from the SOURCE schema, where a variant's payload types and the user types are still visible. The two hash different inputs and do not produce the same string for the same component; neither is compared against the other, and each is stable for its own producer, which is all either one is for.

    Span

    pub(all) struct Span {
    start : Int
    end_ : Int
    } derive(Eq,
    Debug
    )

    A half-open character range in the source that was parsed.

    Character indices, not bytes: they index source.to_array(), the same Array[Char] viewfile slices with and the WHATWG tokenizer counts in, so a span from a slot value and a span from the file agree for any input, astral characters included.

    Step

    pub(all) enum Step {
    FieldStep(String)
    SeqStep(field~ : String, key~ : PathKey)
    SeqAccessStep(seq_field~ : String, key_field~ : String)
    EachRenderItStep(field~ : String, key~ : PathKey)
    } derive(Eq,
    Debug
    )

    Path steps: the ways one value addresses another.

    FieldStep / SeqAccessStep are what an expression addresses (Expr::to_path_item); SeqStep is a field plus a concrete key, and also the pinned form of a SeqAccessStep; EachRenderItStep is an iterated render target that compacts to a SeqStep. Dynamic-var markers live on DispatchStep in the path package.

    EVERY step addresses something. The three that did not — a scope's binds, an @each item's binds, a generic bind frame — are not steps and never were: they said what a rebuilt render stack should have IN SCOPE, which is a different question from where a value lives, and answering it here meant every walk over a path carried a pass-through arm and every reader had to know which steps were real. They are FrameBinds now, carried beside a DispatchFrame's items (path_spec.mbt).

    StepKey

    pub(all) struct StepKey {
    field : String
    key : PathKey?
    } derive(Eq,
    Debug
    )

    A generic {field, key?} descriptor of an addressing step (JS Step.toKey), so tooling can introspect a path without matching on Step.

    StepKey::from_json

    fn StepKey::from_json(j : Json) -> StepKey?

    One step back. None when the object names no field, or names a k that is not a key — a step that cannot say where it points is not a step.

    StepKey::to_json

    fn StepKey::to_json(self : StepKey) -> Json

    One addressing step as JSON: {"f": "rows"}, or {"f": "rows", "k": 1}.

    The shared encoding of a position, and the reason it is here rather than in each of its readers: a refusal, an observer record and a stored execution trace all write the same address, and three copies of two keys is three chances for them to stop agreeing. Short keys because a trace of a real session is mostly these.

    k is ABSENT rather than null for a plain field, which is the distinction StepKey.key is: a sequence step whose key is null is not a field step.

    TplPart

    pub(all) enum TplPart {
    TText(text~ : String, from_macro~ : Bool)
    TExpr(Expr)
    }

    One piece of a $'…' template: literal text, or an interpolated expression.

    There is no third case for a placeholder that failed to parse. The slot parser used to keep one as a hole, which meant every reader of a template had to decide what a hole means; a placeholder that does not parse is a PARSE ISSUE, reported where issues are reported, and the part is dropped.

    from_macro rides on the TEXT case and not only on ELit, because a ^name that resolved to a string is text in the template that contains it — it prints as text and reads as text — and the one bit that still has to survive is whose source it was. That bit is what decides whether the enclosing template counts as a hand-written literal, and therefore whether it may pin a URL origin (tgc/policy/external_url.mbt).
    impl Eq for TplPart
    #alias(TyInfo)
    pub(all) enum Ty {
    TyBool
    TyInt(width~ : Int, signed~ : Bool)
    TyFloat
    TyText
    TyList(Ty)
    TyTuple(Array[Ty])
    TyOption(Ty)
    TyRecord(String)
    TyEnum(String)
    TyVariant(String)
    TyFlags(String, Array[String])
    TySet
    TyOMap(Ty)
    TyComp(String?)
    TyCompProtocols(Array[String])
    TyTable
    TyAny
    } derive(Eq,
    Debug
    )

    What a declared field carries.

    Ty::accepts

    fn Ty::accepts(self : Ty, value : Value) -> Bool

    Whether a runtime value has this declared outer shape. Named records and variants remain permissive because their structural declaration is not carried by Ty; generated decoders perform the deeper check.

    Ty::component_named

    fn Ty::component_named(self : Ty) -> String?

    The component this type names, when it names one.

    greeting? is a slot the way greeting is — is_renderable unwraps an option, so the question "which component" has to unwrap it the same way or the two disagree about the same field.

    Ty::elem

    fn Ty::elem(self : Ty) -> Ty?

    What this type CONTAINS, or None when it contains nothing.

    Strict, and deliberately not the same question iterable_elem answers. That one asks "may a view @each over this?", where any and a child slot must both say yes — a dynamic value may turn out to be a list and a component iterates its own entries, neither knowable at generation time. Answering the two with one method put a meaningless elem: any on 117 fields of the corpus and showed it in the inspector, where the question is the other one: what is in here?

    Ty::in_struct

    fn Ty::in_struct(_self : Ty) -> Bool

    True when this field lives in the state STRUCT — which is every field.

    A slot is a Value field like any other, seeded with Null and filled at make time.

    Ty::is_boolish

    fn Ty::is_boolish(self : Ty) -> Bool

    Whether writing this type in a boolean position can ever decide anything.

    Everything has a truthiness at run time; this asks whether the test can fail. Value::is_truthy answers true for List, Map and Obj unconditionally, so a container in an @show is a test that cannot fail — almost always a forgotten .length or field read.

    A string, a number and an enum are NOT in that set even though they are not booleans: @show=".role" beside @text=".role" is the idiomatic way to hide an empty badge, and @show=".count" hides a zero. Flagging those would cost more in false failures than the real ones are worth — the rule stated at the head of viewgen/check_state.mbt.

    Ty::is_renderable

    fn Ty::is_renderable(self : Ty) -> Bool

    Whether <x render=".field"> can render a value of this type.

    Ty::iterable_elem

    fn Ty::iterable_elem(self : Ty) -> Ty?

    What a view may @each OVER, and what one item of it is.

    Deliberately more permissive than elem, and a different question: this one asks "may a view iterate this?", where any and a child slot must both say yes — a dynamic value may turn out to be a list at run time, and a component iterates its own seq_entries — while elem asks what is actually IN here and answers nothing for both.

    Ty::kind

    fn Ty::kind(self : Ty) -> FieldKind

    The runtime kind: how a value of this type is REPRESENTED, once the shape that distinguishes it no longer matters.

    A projection rather than a stored field, which is the point.

    Ty::members

    fn Ty::members(self : Ty) -> Array[String]

    A closed set's declared members. Empty for every other type, and for a set with open membership — which is a real answer, not a missing one.

    Ty::of_json

    fn Ty::of_json(j : Json) -> Ty

    A declared type read back, or TyAny for anything this cannot make sense of.

    TyAny rather than a failure, and the same answer the flat table gave for an unknown kind: a manifest crossed a trust boundary, and the honest reading of a type a host does not recognize is "cannot say" — which is exactly what any means everywhere else here.

    Ty::show_source

    fn Ty::show_source(self : Ty) -> String

    How the author wrote it. The WIT spelling, because that is what is in the file and what they will edit.

    Ty::slot

    fn Ty::slot(self : Ty) -> String?

    The component a child slot holds, or None for a data field. Some("") is a slot whose component the schema did not name.

    Ty::to_json

    fn Ty::to_json(self : Ty) -> Json

    This type as JSON. k is the case; the rest of the object is that case's payload, which is nothing for most of them.

    Ty::to_mbt_source

    fn Ty::to_mbt_source(self : Ty) -> String

    The MoonBit source of the expression that rebuilds this type.

    What gen splices into a generated SchemaInfo. It is a method on the type rather than a table in the generator, and that is the whole point of there being one Ty: the source form and the value form cannot describe different shapes if one of them IS the shape.

    The constructors are written UNQUALIFIED, and have to be: an enum constructor does not resolve through the pub using re-export that keeps @component.Ty spelling correct, nor through the module-root facade the playground compiles examples against. Bare works in both, because the only position the generator writes one into — a FieldInfo::new argument — already knows the type.

    Ty::zero

    fn Ty::zero(self : Ty) -> Value

    The empty value of this type, as the runtime carries it.

    Type-directed, like the generated <T>State::zero() — which is the point: a default is not an independent fact about a field, so storing one beside the type would be a second thing to keep true. The one default a TYPE cannot give is a child slot's construction arguments, and those are a value the author chooses rather than anything the schema knows.

    This is what an inspector shows in a field's "default" column, reachable from a bare Value.

    UnOp

    pub(all) enum UnOp {
    UNot
    UNeg
    } derive(Eq,
    Debug
    )

    Value

    pub(all) enum Value {
    Null
    Bool(Bool)
    Num(Double)
    Int(Int64)
    Str(String)
    Bin(Bytes)
    Instant(secs~ : Int64, nanos~ : Int)
    List(Array[Value])
    Map(Map[String, Value])
    Fn((Array[Value]) -> Value)
    Obj(&Obj)
    }

    Dynamic runtime value: what eval(stack) reads and returns.

    Aligned with the tgc/1 value, arm for arm, because a format that carries something the host cannot hold is a lossy boundary in the one place there must not be one. tgc/abi's frozen rec group is the other half of this declaration and the two are meant to be read together.

    Three arms are newer than the rest, and each earns its place:

    • Int because the wasm-GC types have a 64-bit integer natively and a double stops being itself past 2^53. It does NOT make the value language two-numbered: tscript still has exactly one number and every arithmetic operation still answers a Num. Int is for a value that arrived from somewhere with integers — a foreign module, a wire format — and is read back out the same way it came in.
    • Bin because a component that holds bytes should not have to spell them as base64 inside a Str and hope every reader agrees which encoding it was.
    • Instant because "when" is the one fact a sandboxed component cannot compute for itself and therefore always receives from somewhere else. A wire type it can be received AS is the difference between one representation and one per host.

    A reader that only knows the older arms is not wrong about them; it is incomplete, and num / str / to_display_string answer for all three so that "incomplete" mostly means "less precise" rather than "broken".
    impl Eq for Value
    impl ToJson for Value
    impl FromJson for Value

    Value::args_of_component_json

    fn Value::args_of_component_json(j : Json, src : &ComponentSource, component? : String, module_? : String, at? : String) -> Map[String, Value]

    A tagged object's fields as constructor args, WITHOUT building it — the half of from_component_json a caller needs when it builds by another route.

    A snapshot is that caller: what to build is already settled (a bundle, a component, an id, and a guest that gets first refusal on its own bytes), and what is missing is only the args — decoded BY DECLARED TYPE, so a field holding an instance comes back as one instead of as a plain Map.

    component~ and module_? say what to assume when the document does not, which is what lets a projection written before there were tags still decode by type. A tag in the document wins, the same way it does in a slot.

    Anything that is not an object has no args: an empty Map, not an error, because the constructor's own defaults are the answer either way.

    Value::as_key

    fn Value::as_key(self : Value) -> PathKey?

    This value AS a sequence key: a string keys a map, an integral number indexes a list. None for everything else — including a non-integral number, which is not an index and must not be rounded into one.

    The bridge between the value world and the addressing world: it is how a .seq[.key] read turns the key FIELD into the key it looks up, and how the renderer names an iterated item in its §Each§ breadcrumb.

    Value::at

    fn Value::at(self : Value, p : Path) -> Value

    The value at a path, or Null at the first step that does not resolve.

    This is the composition, not a new primitive: one-hop reads stay field/item, because building a one-element Path to replace a match costs three allocations. Reach for a Path when the ADDRESS is the thing being passed around — a transaction target, an observed change, a test's assertion site.

    Value::at_opt

    fn Value::at_opt(self : Value, p : Path) -> Value?

    The value at a path, distinguishing "no such place" from a Null stored there — the one distinction at cannot express and no coercer can recover.

    Value::bool

    fn Value::bool(self : Value, default? : Bool) -> Bool

    Value::bool_opt

    fn Value::bool_opt(self : Value) -> Bool?

    Value::call

    fn Value::call(self : Value, args : Array[Value], this? : Value) -> Value

    Call a function value under the Fn convention: element 0 of the argument array is the this slot, which self-pre-bound callees ignore. Null for a non-function.

    The convention was hand-rolled at every call site — match v { Fn(f) =>f([Null, x]) ... } — with the dummy slot spelled out each time.

    Value::call_field

    fn Value::call_field(self : Value, name : String, args : Array[Value]) -> Value

    Call a method OF this value, with this value in the this slot: the $name read followed by the invocation, which is how a view calls one and how a handler filters a list of instances it cannot downcast.

    Value::entries

    fn Value::entries(self : Value) -> Array[(PathKey, Value)]

    The ordered (key, value) entries of any container: a list keyed by index, a map by name, a custom collection by whatever seq_entries says. Empty for anything that is not one (iteration yields no entries then).

    TOOLING and one-off use: this materializes. The renderer's @each keeps indexing List and Map directly, because allocating a tuple per item on every render is not what a convenience is for.

    Value::field

    fn Value::field(self : Value, name : String) -> Value

    Field access that works on Map values and Obj instances alike; Null for anything else (including missing fields).

    Value::field_info

    fn Value::field_info(self : Value, name : String) -> FieldInfo?

    The declared description of one field.

    Value::field_names

    fn Value::field_names(self : Value) -> Array[String]

    Every field name: declaration order for a described instance, key order for a Map, empty for anything else (including an instance that declares nothing — "no schema" is not "no fields", and guessing is what the schema work removed).

    Value::field_opt

    fn Value::field_opt(self : Value, name : String) -> Value?

    A field, or None when there is no such field. Map and Obj answer, anything else has no fields.

    Value::from_component_json

    fn Value::from_component_json(j : Json, src : &ComponentSource) -> Value?

    A tagged document back into an instance, through src.

    None when the root names nothing src can build — a bundle that has not been loaded, a component that was renamed, or a document that is not a tagged object at all.

    Value::from_json

    fn Value::from_json(j : Json) -> Value

    Build a Value from parsed JSON. Total: every JSON shape has a Value.

    It reads the $-tagged forms to_json writes, so the two are inverses for every arm JSON has no shape of its own for — and an object whose OWN keys include $ is escaped as {"$":"map","v":{…}}, without which the discriminator is ambiguous and a reader has to guess.

    It is not the inverse on numbers, and that is deliberate. A plain JSON number decodes to Num, because a JSON number IS a double and pretending otherwise past 2^53 would invent precision the input never had. A producer that needs an Int back writes the tagged form, which to_json always does — which is why the tagged form is not an option a producer may skip.

    One consequence worth naming, since this is also the bridge a DOM CustomEvent detail crosses: a page that sends {"$":"bin","v":"…"} now gets a Bin rather than a two-key map. That is the right answer — it is what the sender wrote — and the three arms it can mint are inert data with no authority of their own.

    Value::handler

    fn Value::handler(self : Value, bucket : HandlerBucket, name : String) -> Handler?

    The handlers a value carries: component instances answer through the Obj trait, pure data has none.

    Value::identity

    fn Value::identity(self : Value) -> ObjId?

    This value's render-cache bucket, when it is an instance that tracks one.

    None for every plain value — a Map render site, a component-less embedding — and that is the answer the render cache reads as "decline": there is nothing here whose generations can be told apart, so keying on it would only build a key and miss.

    Value::index

    fn Value::index(self : Value, i : Int, default? : Value) -> Value

    v.index(2) — an item by position.

    Value::int

    fn Value::int(self : Value, default? : Int) -> Int

    Value::int_opt

    fn Value::int_opt(self : Value) -> Int?

    Value::is_truthy

    fn Value::is_truthy(self : Value) -> Bool

    Truthiness: Null/false/0/NaN/"" are false; lists, maps and functions are always true. The truthy? predicate differs on purpose: it treats empty collections as falsy (see pred_truthy).

    Value::item

    fn Value::item(self : Value, key : PathKey, default? : Value) -> Value

    An item by key, or the default.

    Value::item_opt

    fn Value::item_opt(self : Value, key : PathKey) -> Value?

    An item by key: a list index, a map key, or whatever a custom collection resolves through item. None when there is no such item.

    Value::key

    fn Value::key(self : Value, k : String, default? : Value) -> Value

    v.key("id") — an item by name. Distinct from field: a Map answers both, but a component instance keys its SEQUENCE here and its FIELDS there.

    Value::list

    fn Value::list(self : Value) -> Array[Value]

    The list payload; [] for non-lists (shared empty NOT returned — fresh).

    Value::list_opt

    fn Value::list_opt(self : Value) -> Array[Value]?

    Value::map

    fn Value::map(self : Value) -> Map[String, Value]

    The map payload; empty for non-maps (fresh, like Value::list).

    Value::map_opt

    fn Value::map_opt(self : Value) -> Map[String, Value]?

    Value::member_at

    fn Value::member_at(self : Value, name : String, stack : &Stack) -> Value?

    Read a virtual member from the owning component's render context. This is the internal counterpart of property: private properties participate, and ordinary fields remain the fallback.

    Value::method_at

    fn Value::method_at(self : Value, name : String, stack : &Stack) -> Value?

    A $name read, asked with the stack it is being asked from.

    The same question field asks — a compute surfaces as a pre-bound Fn on the instance — with the one thing a Fn cannot carry added back: the environment a body needs to answer a *name in it. Everything that is not an Obj answers exactly as field_opt does, because only an Obj has a body to run.

    Value::mutate_member

    fn Value::mutate_member(self : Value, name : String, operation : String, args : Array[Value]) -> Outcome

    Apply a source-level operation to a member on behalf of its owning view.

    Value::num

    fn Value::num(self : Value, default? : Double) -> Double

    Value::num_opt

    fn Value::num_opt(self : Value) -> Double?

    Value::property

    fn Value::property(self : Value, name : String) -> Value

    Value::property_opt

    fn Value::property_opt(self : Value, name : String) -> Value?

    Read a component's public abstract property. Maps deliberately do not participate: a property is a component interface, not another spelling of ordinary record lookup.

    Value::protocol_property

    fn Value::protocol_property(self : Value, protocol_id : String, member_name : String, stack : &Stack) -> Value

    Read a protocol property through its explicit local-property binding. A failed gradual assumption returns Null and reports the resolution; it never tears down rendering.

    Value::schema

    fn Value::schema(self : Value) -> SchemaInfo?

    What this value DECLARES, when it is a component instance that says.

    Value::set_member

    fn Value::set_member(self : Value, name : String, v : Value) -> Outcome

    Apply a private-or-public property transition on behalf of the component's own view.

    Value::set_property

    fn Value::set_property(self : Value, name : String, v : Value) -> Outcome

    Apply a public synchronous property transition.

    Value::set_property_at

    fn Value::set_property_at(self : Value, path : Path, name : String, v : Value) -> Outcome

    Apply a property setter to a nested value and rebuild every parent in one pure copy-on-write operation.

    A missing path/property or a refusal rebuilds nothing. This is the component-side primitive behind synchronous parent-to-child property writes: the child transition either contributes its whole successor to the parent's successor or the parent keeps the original tree.

    Value::size

    fn Value::size(self : Value, default? : Int) -> Int

    How many items, or 0. The total form of size_of.

    Value::snapshot

    fn Value::snapshot(self : Value) -> Map[String, Value]

    name -> value for every declared field, in declaration order.

    What every consumer that wanted to SHOW an instance had been faking: the inspector read the names off a Components registry, the example builder took them as a parameter, the host parsed them out of a JSON projection.

    Value::str

    fn Value::str(self : Value, default? : String) -> String

    Value::str_opt

    fn Value::str_opt(self : Value) -> String?

    Value::to_component_json

    fn Value::to_component_json(self : Value, claim? : (Value, String) -> Json?) -> Json

    This value as a tagged JSON document, recursively and schema-driven.

    claim~ sees every instance and its pointer BEFORE any field of it is read; answering Some(j) writes j in place of the walk. It runs first rather than after because the case it exists for is a component whose state is not the caller's to read, and reading a foreign guest's fields would cross a boundary once per field before the hook could say no.

    Value::to_display_string

    fn Value::to_display_string(self : Value) -> String

    ${v} template-interpolation semantics. Approximations: List joins elements with ","; Map and Fn render as opaque markers ("[object Object]" / function source are not worth mirroring).

    Value::to_json

    fn Value::to_json(self : Value) -> Json

    Json shape of a Value.

    A DESCRIBED instance projects to its declared fields, recursively — which is what makes a state dump JSON rather than a debug string.

    An instance that declares nothing is still null: with no schema there is no field list to project, and inventing one is what the schema work removed. Fn stays null unconditionally, so a method or an unrendered handler inside a described instance projects as null rather than taking the whole object with it.

    Value::trigger_at

    fn Value::trigger_at(self : Value, name : String, stack : &Stack) -> Value?

    The render-time twin of method_at: @when, @enrich-with, @loop-with.

    Value::with_at

    fn Value::with_at(self : Value, p : Path, v : Value) -> Value

    Copy-on-write write at a path, total: the SAME value back when the path does not resolve (Path::set_value's own contract).

    Value::with_field

    fn Value::with_field(self : Value, name : String, v : Value) -> Value

    Copy-on-write field write, total: the value unchanged when the field cannot be written.

    Value::with_field_opt

    fn Value::with_field_opt(self : Value, name : String, v : Value) -> Value?

    Copy-on-write field write; None when there is no such field to write (no such field on an instance, not a container at all). The partial form is what step_put needs: a step that cannot be addressed must leave the whole tree untouched rather than silently write nothing.

    Value::with_item

    fn Value::with_item(self : Value, key : PathKey, v : Value) -> Value

    Copy-on-write item write, total. Same identity contract as with_field.

    Value::with_item_opt

    fn Value::with_item_opt(self : Value, key : PathKey, v : Value) -> Value?

    Copy-on-write item write; None when the key addresses no item (an index out of range, a key of the wrong kind for the container).

    bad_payload

    fn bad_payload(asked : String, declared : String, args : Array[Value]) -> Unit

    Report a dispatch whose arguments did not fit the payload its name declares.

    Raised from a generated from_dispatch, which is the one place that holds both halves: the runtime arguments, and the declared spelling the schema wrote. declared is that spelling — "Int, String", or "" for a case that declares no payload — and it is baked in at generation time, because nothing at runtime can reconstruct it.

    The decode's answer is unchanged: the case falls into Unknown, and an update that does not claim it answers Unhandled exactly as before. This only makes the failure SAYABLE — a mismatch used to be indistinguishable from a name nobody sent.

    broken_domain

    fn broken_domain(all : Array[FieldDomain], field : String, v : Value, fields : Map[String, Value]) -> Domain?

    The first domain of field that v breaks, or None.

    The FIRST rather than all of them, because a rejection needs one reason to report and a reader fixes them one at a time.

    broken_domain_sentence

    fn broken_domain_sentence(d : FieldDomain, fields : Map[String, Value]) -> String

    What first_broken_domain found, as the sentence to say about it.

    A convenience over domain_sentence and worth its line: every caller of the first has the pair in hand and has to dig the value back out of the map to call the second, and three callers digging it out three times is three chances to dig out the wrong one.

    broken_domains

    fn broken_domains(all : Array[FieldDomain], fields : Map[String, Value]) -> Array[String]

    Every field whose CURRENT value is outside its declared domain.

    The whole-state question, asked after a transition so a hand-written handler that assigns a field directly is held to the same declaration a generated setter is. Sorted, for the reason SchemaInfo.invariants is: which domain broke is part of the answer, and a report that depended on declaration order would move when an unrelated clause was added above it.

    builtin

    fn builtin(name : String) -> Builtin?

    The builtin a name denotes, or None when nothing does.

    builtin_names

    fn builtin_names() -> Array[String]

    Every builtin name in BYTE order — the vocabulary a "did you mean" search ranges over, and the reason it is public rather than a private table.

    Not Array::sort: MoonBit's Compare for String is length-first, which would answer null?, empty?, falsy?, equals?, truthy?. That is still deterministic, and it reads as unordered to the person the list is for.

    closest_name

    fn closest_name(name : String, names : Array[String], limit~ : Int) -> String?

    The nearest of names to name, when one is close enough to suggest.

    limit is the caller's, and it is the one thing that legitimately differs: a fixed handful of command and flag names can afford a generous two edits, where field names are as long as the author made them and want a threshold that grows with the word. Suggesting nothing is better than suggesting the wrong thing — a reader trusts a "did you mean".

    component_key

    let component_key : String

    The discriminator: the component a tagged object names.

    Collision-free by construction. A declared field name cannot begin with $ — the state language's identifier start is alpha-or-underscore — and neither can a WIT identifier, so no component can declare a field that shadows this.

    default_route

    fn default_route() -> Array[Leg]

    The default route is dyn lex and is written HERE, once. Every other package that needs it asks for it rather than spelling two arms of an enum in its own order — a default route two packages disagree about is the kind of difference that shows up as a component answering in one build and not in another.

    A function rather than a let, because a route is an Array and a shared one could be appended to by whoever received it.

    domain_failed

    fn domain_failed(handler~ : String, field~ : String, sentence? : String, state? : Value) -> Unit

    A write left a field outside its declared domain, so it was abandoned.

    field goes where a rule's name goes, and that is the point rather than a convenience: a where has no name, and what a reader needs is the FIELD and the relation it left. sentence is composed from the relation (domain_sentence) rather than written by an author, which is why a where carries no format.

    domain_holds

    fn domain_holds(domain : Domain, v : Value, fields : Map[String, Value]) -> Bool

    Whether v is in domain, read against the state it would live in.

    UNKNOWN IS NOT WRONG — the same rule an invariant follows. A relation whose target field is absent, or holds something the relation cannot read, answers true: a domain that could not be evaluated has not rejected anything. The alternative would turn a schema this package cannot fully see — a dynamic component, a partially decoded state — into a component that refuses every write.

    domain_sentence

    fn domain_sentence(domain : Domain, field : String, v : Value, fields : Map[String, Value]) -> String

    What a broken domain says, with the values that broke it.

    Composed rather than authored, and that is why a where carries no format. A rule needs a hand-written sentence because an arbitrary boolean cannot say why it failed; a relation knows exactly what it wanted and what it got, so a sentence written by hand could only be less specific than this one.

    domains_of

    fn domains_of(all : Array[FieldDomain], field : String) -> Array[Domain]

    The domains a write to field has to satisfy, conjoined.

    domains_of_json

    fn domains_of_json(j : Json) -> Array[FieldDomain]

    The domains a manifest declares.

    UNKNOWN IS NOT WRONG, the same rule the evaluator follows and for a sharper reason here: this reads a document a GUEST wrote, and a guest built against a later version of this vocabulary will name relations this host has never heard of. An entry that cannot be read is DROPPED rather than raised — a host that refused to load a bundle over a clause it could not enforce would turn every addition to the vocabulary into a compatibility break, and one that enforced a guess would refuse writes the guest holds to be legal.

    domains_to_json

    fn domains_to_json(all : Array[FieldDomain]) -> Json

    Every domain as JSON, for a manifest.

    edit_distance

    fn edit_distance(a : String, b : String) -> Int

    Damerau-Levenshtein: an adjacent transposition counts as ONE edit.

    escape_of

    fn escape_of(c : Char) -> Char?

    The escape letter a character is written as inside a '…' literal, when it is written as one.

    A newline in a literal is printed as \n rather than as itself: the source round-trips either way, but a declaration that grew three lines because a seed carries a paragraph is a declaration nobody can read.

    field_domains_to_mbt_source

    fn field_domains_to_mbt_source(all : Array[FieldDomain]) -> String

    A field-domain list as MoonBit source: what a generated SchemaInfo carries under domains~.

    first_broken_domain

    fn first_broken_domain(all : Array[FieldDomain], fields : Map[String, Value]) -> FieldDomain?

    The first domain the WHOLE state breaks, with the field it is about.

    One function and not three, because there are three places that ask it and they have to get the same answer: the runtime's post-transition door, the guard gen weaves into a generated arm, and the dynamic-component host holding a guest's successor. A domain the woven guard admitted and the runtime then refused would be a component that abandons a transition its own compiled code said was fine — which is exactly the class of bug a second reading of one declaration produces.

    Source order, not sorted: this answers WHICH ONE to report, and a reader fixes them one at a time. broken_domains is the other question — every field at once — and sorts for its own reasons.

    fnv1a_hex

    fn fnv1a_hex(s : String) -> String

    FNV-1a over a string, as sixteen hex digits.

    The one copy. Not cryptographic and does not need to be: every caller uses it to tell apart things a human wrote — a schema's shape, a module and the config it was resolved with, an instance's contents — and a collision costs a cache miss rather than a lie. Four hand-written copies of the same eight lines is four chances for one of them to be a different hash.

    instant_of_rfc3339

    fn instant_of_rfc3339(text : String) -> (Int64, Int) raise BadInstant

    The reverse. Z and a numeric offset both parse; the offset is APPLIED and not kept, because what comes back is an instant and an instant has no zone.

    instant_to_rfc3339

    fn instant_to_rfc3339(secs : Int64, nanos : Int) -> String

    RFC 3339, always UTC.

    moonbitlang/x/time owns the calendar — turning 1 725 000 000 into a date is exactly the arithmetic nobody should write twice — and this owns the spelling, which the library does not: ZonedDateTime::to_string appends a zone name, and RFC 3339 wants an offset.

    invariant_failed

    fn invariant_failed(handler~ : String, pred~ : String, sentence? : String, state? : Value) -> Unit

    An invariant did not hold after the body ran. Same abandonment, different reason: the rule is the component's rather than this handler's.

    is_digit

    fn is_digit(c : Char) -> Bool

    An ASCII decimal digit. Deliberately not Char::is_numeric, which admits every digit Unicode has: a number in these languages is ASCII, and a lexer that accepted Devanagari digits would produce tokens no parser can read.

    is_ident_char

    fn is_ident_char(c : Char) -> Bool

    A letter, digit or _: what an identifier may continue with.

    is_ident_start

    fn is_ident_start(c : Char) -> Bool

    A letter or _: what an identifier may begin with.

    is_type_name

    fn is_type_name(s : String) -> Bool

    A name starting A-Z reads as a component TYPE; anything else is a value.

    One rule, written once, because every layer that carries a name needs the same partition — the value parser telling a type token from a name, a provide key deciding whether "self" is the only legal value, a card's state block saying the same thing in text. It is also what lets types and values share one binding frame: their keyspaces cannot collide, so nearest-ancestor-wins falls out of frame order for both without a second stack.

    line_count

    fn line_count(s : String) -> Int

    How many newlines s contains — one less than the number of lines when it does not end in one, which is why it is named for what it counts.

    module_key

    let module_key : String

    The bundle a tagged object came from, when its writer knew.

    A separate key rather than a module/Component join, because a module name may contain a slash — which is exactly why ComponentRef::to_id is a label with no way back. Absent means "resolve in whatever namespace you are", which is the only thing a document written without a host can mean.

    mutator_name

    fn mutator_name(verb : String, field : String) -> String

    The name of a field's generated mutator: count + set -> setCount.

    The convention lives HERE, in one function, because two places have to agree on it and neither can see the other. component() builds the mutators by concatenating it, and the state editor — which holds a bare Value and calls them by name through Obj::member — reconstructed the same string from its own copy. Two spellings of one convention, either of which could have been changed alone.

    no_span

    let no_span : Span

    The empty span, for a value with no source of its own — a ^macro variable's expansion, a generated IR module's rebuilt AST, or a value built by hand.

    on_runtime_notice

    fn on_runtime_notice(f : (RuntimeNotice) -> Unit) -> (() -> Unit)

    Switch the channel on. Returns the uninstall, which puts back whatever listener was there before — so a test that installs one inside another's lifetime cannot silently keep it.

    operand_source

    fn operand_source(e : Expr) -> String

    postcondition_failed

    fn postcondition_failed(handler~ : String, pred~ : String, sentence? : String, state? : Value) -> Unit

    A postcondition did not hold after the body ran, so the transition was abandoned whole — state and effects together. state is the SUCCESSOR that was thrown away, which is the one worth looking at.

    precondition_failed

    fn precondition_failed(handler~ : String, pred~ : String, sentence? : String, state? : Value) -> Unit

    A precondition did not hold, so the handler declined before touching anything. state is the state as it ARRIVED — nothing has moved yet.

    protocol_mismatch

    fn protocol_mismatch(n : RuntimeProtocolNotice) -> Unit

    Report an exercised gradual protocol assumption that failed. Unlike a refusal, this is delivered immediately: the resolution already kept the UI usable, so there is no dispatch-chain deduplication to perform.

    refuse

    fn refuse(r : Refusal) -> Unit

    Report a refusal. A no-op when nothing is listening.

    Inside a dispatch the record is HELD rather than delivered, so the one that decided is the one that escapes. A refusal raised outside any dispatch — a render-time name that nothing answers — is its own chain end and goes straight out.

    refusing

    fn refusing() -> Bool

    Whether anything is listening.

    Producers ask this before they build a record, and take the warn path when the answer is no. It is the reason a rejected state can be carried at all: nobody pays for it until somebody wants it.

    route_label

    fn route_label(route : Array[Leg]) -> String

    A route as it is written: the leg words, space-separated. [Dyn, Lex] is "dyn lex", and the empty route is the empty string.

    route_lookup

    fn[T] route_lookup(route : Array[Leg], lex : () -> T?, dyn_ : () -> T?) -> T?

    Walk a route's legs in order and answer the first one that resolves.

    The one walk every name question shares, whatever it is asking about: the legs are LAZY, so a leg that is never reached is never paid for, and the array IS the walk order, so [Lex, Dyn] asks the registration scope first. An empty route answers None rather than falling back to the default — "ask nothing" is a thing a caller can mean.

    Generic because the two environments answer different things: a value leg answers a Value, a type leg answers a component id. There is no unknown-leg arm to write, which is the one place this is simpler than the JS it is ported from: Leg is closed.

    size_of

    fn size_of(v : Value) -> Int?

    size_of: .size (immutable collections) or .length (string/array).

    A custom collection answers too, through size. An instance that is NOT a sequence still answers None, which is the honest reading: a component has fields, not a size.

    step_get

    fn step_get(node : Value, step : Step) -> Value?

    step_keys_label

    fn step_keys_label(keys : Array[StepKey]) -> String

    Addressing steps as readable text: value.rows[1].title.

    Over StepKey rather than Step, because that is the projection a transaction is RECORDED as (ObserveRecord.path_keys) — so a log line and a Path print the same way without the log having to keep the Path.

    step_with_key

    fn step_with_key(step : Step, key : PathKey) -> Step

    Key a step with the si/sk an §Each§ meta carried (used by event reconstruction's applyKey): a plain field access under a keyed meta addresses the keyed item. Steps that carry their own key (or no field) are returned unchanged.

    target_bind

    let target_bind : String

    The name new writes and the statements under it read: cur.

    Reserved, and named once rather than spelled in five packages, because the checker refuses to let an enrich bind it, the interpreter refuses to let it escape into a view, and both are talking about the same name.

    warn

    fn warn(msg : String) -> Unit

    Report a runtime warning through warn_hook.

    warn_hook

    let warn_hook :
    Ref
    [(String) -> Unit]

    Where runtime warnings go. Defaults to println; a host can redirect it — e.g. into an error pane or the browser console — without threading a context through eval.