Scaffold a parameterized starter node — a bound-param build closure is not learnable from public docs #183

Closed
opened 2026-07-02 22:25:13 +02:00 by Brummel · 2 comments
Owner

A new project's only node-authoring template is the scaffolded Identity node, which is param-less: its build closure never reads a bound param. There is no public example anywhere (README, project-layout, scaffold output) of a build closure consuming a bound param, so a downstream author cannot write their first tunable node — the core authoring act — from the public interface alone. The milestone fieldtest rated this its highest-value gap (finding F2, fieldtests/milestone-project-environment/FINDINGS.md, 2026-07-02): the fieldtester could author a param-less Negate node from the template, but a parameterized node would have required reading engine source, which the consumer contract forbids.

Likely shape: extend the scaffold's starter lib.rs with (or swap the template to) one small parameterized node — e.g. a Scale node with a bound factor: f64 — showing the param declaration, the bind-able schema, and the build closure reading the bound value; the starter blueprint can bind it so aura run exercises it out of the box. Per the #181 canon (templates are the canonical authoring shape and evolve freely; the 0102 fixture stays frozen), this is a template-side edit with no fixture churn.

  • depends on: nothing
  • context: post-milestone polish from the green project-environment fieldtest; the authoring loop works, but only for param-less nodes when learned from public docs alone.
A new project's only node-authoring template is the scaffolded `Identity` node, which is param-less: its build closure never reads a bound param. There is no public example anywhere (README, project-layout, scaffold output) of a build closure consuming a bound param, so a downstream author cannot write their first *tunable* node — the core authoring act — from the public interface alone. The milestone fieldtest rated this its highest-value gap (finding F2, `fieldtests/milestone-project-environment/FINDINGS.md`, 2026-07-02): the fieldtester could author a param-less `Negate` node from the template, but a parameterized node would have required reading engine source, which the consumer contract forbids. Likely shape: extend the scaffold's starter `lib.rs` with (or swap the template to) one small parameterized node — e.g. a `Scale` node with a bound `factor: f64` — showing the param declaration, the `bind`-able schema, and the build closure reading the bound value; the starter blueprint can bind it so `aura run` exercises it out of the box. Per the #181 canon (templates are the canonical authoring shape and evolve freely; the 0102 fixture stays frozen), this is a template-side edit with no fixture churn. - depends on: nothing - context: post-milestone polish from the green project-environment fieldtest; the authoring loop works, but only for param-less nodes when learned from public docs alone.
Brummel added the feature label 2026-07-02 22:25:13 +02:00
Brummel added this to the Triage harvest 2026-07 — surface honesty & authoring ergonomics milestone 2026-07-09 17:31:16 +02:00
Author
Owner

Triage 2026-07-09 (tree at 68317ec) — unchanged gap, and the model to copy now ships in-repo:

  • The scaffold's LIB_RS template still authors only the param-less Identity (params: vec![], build closure |_| Box::new(Identity::new()) at crates/aura-cli/src/scaffold.rs:143, template :111-187).
  • The exact proposed shape exists since the demo retirement: crates/aura-std/src/scale.rs binds a factor param and reads it in the build closure (|p| Box::new(Scale::new(p[0].f64())), landed with 257ab0b). aura-std is engine source, which the downstream-consumer contract excludes from the public surface, so the public-docs gap stands.
  • The starter blueprint (SIGNAL_JSON) shows JSON-side param binding but not the Rust-side read; no public doc covers PrimitiveBuilder build-closure param access.
  • Template-side edit; only templates_render_without_leftover_tokens asserts template content, so fixture churn is minimal. Acceptance: the rendered scaffold lib.rs contains a param-bearing node and the starter blueprint binds it so aura run exercises the path.
Triage 2026-07-09 (tree at 68317ec) — unchanged gap, and the model to copy now ships in-repo: - The scaffold's LIB_RS template still authors only the param-less Identity (`params: vec![]`, build closure `|_| Box::new(Identity::new())` at crates/aura-cli/src/scaffold.rs:143, template :111-187). - The exact proposed shape exists since the demo retirement: crates/aura-std/src/scale.rs binds a factor param and reads it in the build closure (`|p| Box::new(Scale::new(p[0].f64()))`, landed with 257ab0b). aura-std is engine source, which the downstream-consumer contract excludes from the public surface, so the public-docs gap stands. - The starter blueprint (SIGNAL_JSON) shows JSON-side param binding but not the Rust-side read; no public doc covers PrimitiveBuilder build-closure param access. - Template-side edit; only templates_render_without_leftover_tokens asserts template content, so fixture churn is minimal. Acceptance: the rendered scaffold lib.rs contains a param-bearing node and the starter blueprint binds it so `aura run` exercises the path.
Author
Owner

Design decision: swap the starter node, don't add a second one (/boss)

Fork: teach the bound-param build closure by (a) adding a Scale node
alongside the existing param-less Identity in the scaffold's src/lib.rs, or
(b) swapping Identity out for one param-bearing node.

Decision: (b) swap. The scaffold's src/lib.rs ships exactly one node, and
it becomes param-bearing — a Scale node with a bound factor: f64 (namespaced
<ns>::Scale, modeled on the std Scale), declaring the factor ParamSpec
and reading it in the build closure (|p| Box::new(Scale::new(p[0].f64()))). The
starter blueprint's terminal passthrough node is retargeted from <ns>::Identity
to <ns>::Scale with factor bound, so aura run exercises the bound-param
path out of the box. Basis: the single copyable node a newcomer learns from
should itself demonstrate the param-reading closure with no param-less decoy
beside it — the F2 gap is precisely "no public example of a build closure
consuming a bound param," and one tunable node teaches it with zero redundancy.
Per #181 this is template-side only; the frozen 0102 fixture is untouched.

## Design decision: swap the starter node, don't add a second one (/boss) Fork: teach the bound-param build closure by (a) *adding* a `Scale` node alongside the existing param-less `Identity` in the scaffold's `src/lib.rs`, or (b) *swapping* `Identity` out for one param-bearing node. Decision: **(b) swap.** The scaffold's `src/lib.rs` ships exactly one node, and it becomes param-bearing — a `Scale` node with a bound `factor: f64` (namespaced `<ns>::Scale`, modeled on the std `Scale`), declaring the `factor` `ParamSpec` and reading it in the build closure (`|p| Box::new(Scale::new(p[0].f64()))`). The starter blueprint's terminal passthrough node is retargeted from `<ns>::Identity` to `<ns>::Scale` with `factor` bound, so `aura run` exercises the bound-param path out of the box. Basis: the single copyable node a newcomer learns from should itself demonstrate the param-reading closure with no param-less decoy beside it — the F2 gap is precisely "no public example of a build closure consuming a bound param," and one tunable node teaches it with zero redundancy. Per #181 this is template-side only; the frozen 0102 fixture is untouched.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#183