nustack

Form

A Form is a typed surface wrapped around a Nu node. It doesn't compute; it curates. Given a wrapped node, a Form offers the set of methods that would build observable compositions on top of it - and refuses the rest.

What a Form is

  • wraps a single Nu node (a Ref or a value-node);
  • exposes a typed surface (methods, operators, accessors) matched to the wrapped node's shape;
  • each call constructs an Interaction on top of the wrapped node and returns a new Form.

A Form is itself a Nu - it participates in the tree. It doesn't do work; it chains through to the underlying Interactions.

Observability gate

The danger with a naive typed surface: a method builds a non-observable node and hands the user a validation failure after perfectly reasonable-looking code. So the surface a Form may offer is gated by the observability matrix.

The gate splits by what the Form wraps.

Value-node - a Literal, or any yielding non-Ref node. Only the yielding face is reachable:

  • Query methods - yield, always observable. Offered.
  • Action methods - offered, but addressless: they degrade to a Query (the mutate half evaporates, the yield survives).
  • Command methods - never offered. A Command over a value-node voids -> non-observable -> invalid.

So Literal(5) + 10 and Literal([1,2,3]).pop() (degrades to a Query yielding 3) are fine; Literal([1,2,3]).append(4) is not offered - it would void.

Ref-node - the full face: Query + Command + Action. A Ref is an address, so a mutation lands.

This is the observability matrix from foundations resurfacing one layer up: the Form gate is the same value-node-versus-Ref split, applied to which methods a wrapper may expose.

Immutability as a policy

A Form's surface is fixed by what it wraps - value-node or Ref-node - not by a separate mutable / immutable axis. Immutability, when useful, is a policy on top: narrow a Ref's full face to the value-node's yield-only face. An immutable Ref voluntarily wears the value-node's mask - the same partition, applied by choice instead of by necessity.

Unknown surface

When a value-node's type is genuinely opaque - a dynamically-typed source, an unresolvable annotation - the Form degrades to an unknown surface. Every operation on it returns another unknown-surface Form. The chain never explodes; the user keeps composing. Mutation methods remain gated by the value-node rule: only yielding operations reach through.

Why a layer, not core

The model works without Forms - a program can always be written as raw Interactions. Forms make it ergonomic. They are the typed-surface discipline over Refs and value-nodes; the algebra underneath doesn't change.

On this page