From 5d967a6a175f2d9c1ea005502ca5e7deed9c22fa Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 6 Sep 2026 16:57:14 +0000 Subject: [PATCH] Adopt the input and source vocabulary --- node-graph/rfcs/attribute-model.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/node-graph/rfcs/attribute-model.md b/node-graph/rfcs/attribute-model.md index b8695c076d..b861d0e880 100644 --- a/node-graph/rfcs/attribute-model.md +++ b/node-graph/rfcs/attribute-model.md @@ -310,7 +310,7 @@ not. The tuple form composes with laziness: a lazy input declared each evaluation, so a kernel can branch on another input's attribute without evaluating the branch it rejects. It is a read declaration only: the lazy input's fields do not pass through to the output, since -the kernel controls whether and how often the edge is evaluated; +the kernel controls whether and how often the input is evaluated; forwarding a lazy input's attributes is routing. The rest of the authoring surface composes. Categories, per-parameter @@ -561,18 +561,18 @@ every lift, one copy per invocation. | Signature form | Meaning | Lowering | | --- | --- | --- | | first non-context param | primary input | carrier record | -| `_: ()` | no primary input | no carrier edge | +| `_: ()` | no primary input | no carrier input | | `element: T` (unbounded, returned first) | explicit passthrough | erased byte carry, where `T` is instantiated with a zero-sized token, so the routing is checked by the type system and costs nothing | | `element: Concrete` / bound | element read | field read at offset 0, monomorphized per implementations list, binds level 0 | | `(x, a): (X, Attr)` | input with attribute reads | the value as its ordinary lowering; each `Attr` an offset read into that input's record, or the default constant | -| `(_, a): ((), Attr)` | attribute-only input | wired record edge with unit element; the attribute is the payload | +| `(_, a): ((), Attr)` | attribute-only input | a wired record input with unit element; the attribute is the payload | | `Attr` in the return tuple | attribute write | offset write into the output record | | `RemoveAttr` in the return tuple | attribute delete | the name leaves the output layout; functionally a write of the default | | `OwnedAttr` in an async source's return tuple | owned attribute write | the value crosses the future boundary as a deep copy taken before the first await, and parks into the serving arena at every lift; exhaustion surfaces as a poll | -| `keys: IList` | whole-extent input | wired edge, evaluated over its extent into a view | -| plain parameters | wired value inputs | ordinary wired edges; attributes on their wires do not flow | +| `keys: IList` | whole-extent input | a wired input, evaluated over its extent into a view | +| plain parameters | wired value inputs | ordinary wired value inputs; attributes on their wires do not flow | | `impl Node, Output = Concrete>` | lazy value input | the value flows, attributes do not | -| `impl Node, Output = (T, Attr, ..)>` | lazy input with attribute reads | each eval yields the element plus the declared reads, offsets resolved against that edge's layout; a read declaration only, and no field pass-through | +| `impl Node, Output = (T, Attr, ..)>` | lazy input with attribute reads | each eval yields the element plus the declared reads, offsets resolved against that input's layout; a read declaration only, and no field pass-through | | `impl Node, Output = T>` (unbounded) | source of an opaque record family | routing, see below | | `-> IList` with a lazy subject and `DeriveCtx` | per-copy level production | the kernel splits the index and evaluates the subject at the pushed level | | `-> IList` with a carrier subject | per-lane level production | the carrier binds once for the run; the kernel computes each lane's own fields | @@ -640,10 +640,10 @@ sources are the lazy inputs whose `Output` is the generic; the element passthrough is the same mechanism with the carrier as the family's only source. Wiring computes the union of the sources' layouts and a translation plan per source (field moves plus default fills). The -kernel-facing handles wrap the edges the same way the error dialect -wraps status plumbing: evaluating a source evaluates its edge at the +kernel-facing handles wrap the inputs the same way the error dialect +wraps status plumbing: evaluating a source evaluates its input at the unchanged context and yields a value carrying the resulting record, -either through the plan into that source's own buffer, or, when the +either through the plan into a claim of that source's own, or, when the source's layout already equals the union, by forwarding the record pointer untouched. The forwarding case compiles to a conditional move plus a tail call; the +4.7ns per lane of a two-branch switch is the @@ -652,12 +652,12 @@ costs +6.5ns per lane at eight attributes. The kernel routes these values as ordinary Rust values. It can evaluate any source any number of times, hold several results at once (per-source -buffers keep them valid side by side), pass them through helper +claims keep them valid side by side), pass them through helper functions, and return any of them. The returned value's record is the node's output, so provenance is carried by the value itself: element and attributes travel together, and returning a result obtained before some later evaluation is well-defined. A value is live until its own source -is evaluated again, which overwrites that source's buffer; a kernel that +is evaluated again, which reclaims that source's claim; a kernel that needs two results of one input side by side declares the input twice. The values are opaque and unforgeable, and inspecting one requires bounds on the generic, which is element access and monomorphization as @@ -810,7 +810,7 @@ the wiring-computed byte plans, where it is irreducible. convergence (merge unions them, defaults answer switch mismatches) and the resolver is untouched. - The numbers cited throughout come from a reference prototype with - type-erased node edges (the indirect calls were verified in the + type-erased node inputs (the indirect calls were verified in the disassembly), thin LTO, 64k-lane workloads, and best-of-nine timing. Chain results use ten nodes and eight f64 attributes.