behavior-contracts 0.8.6 → 0.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/cli-contract.yaml +189 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +76 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/codegen.d.ts +6 -0
  7. package/dist/commands/codegen.d.ts.map +1 -0
  8. package/dist/commands/codegen.js +39 -0
  9. package/dist/commands/codegen.js.map +1 -0
  10. package/dist/generated/commands.d.ts +8 -0
  11. package/dist/generated/commands.d.ts.map +1 -0
  12. package/dist/generated/commands.js +55 -0
  13. package/dist/generated/commands.js.map +1 -0
  14. package/dist/generated/contract.d.ts +3 -0
  15. package/dist/generated/contract.d.ts.map +1 -0
  16. package/dist/generated/contract.js +5 -0
  17. package/dist/generated/contract.js.map +1 -0
  18. package/dist/generated/index.d.ts +7 -0
  19. package/dist/generated/index.d.ts.map +1 -0
  20. package/dist/generated/index.js +7 -0
  21. package/dist/generated/index.js.map +1 -0
  22. package/dist/generated/program.d.ts +17 -0
  23. package/dist/generated/program.d.ts.map +1 -0
  24. package/dist/generated/program.js +117 -0
  25. package/dist/generated/program.js.map +1 -0
  26. package/dist/generated/schemas.d.ts +2 -0
  27. package/dist/generated/schemas.d.ts.map +1 -0
  28. package/dist/generated/schemas.js +3 -0
  29. package/dist/generated/schemas.js.map +1 -0
  30. package/dist/generated/types.d.ts +35 -0
  31. package/dist/generated/types.d.ts.map +1 -0
  32. package/dist/generated/types.js +3 -0
  33. package/dist/generated/types.js.map +1 -0
  34. package/dist/generator/core.d.ts +28 -0
  35. package/dist/generator/core.d.ts.map +1 -1
  36. package/dist/generator/core.js +7 -0
  37. package/dist/generator/core.js.map +1 -1
  38. package/dist/generator/emit-shared-debox.d.ts +108 -0
  39. package/dist/generator/emit-shared-debox.d.ts.map +1 -0
  40. package/dist/generator/emit-shared-debox.js +117 -0
  41. package/dist/generator/emit-shared-debox.js.map +1 -0
  42. package/dist/generator/emit-typed-native-go.d.ts.map +1 -1
  43. package/dist/generator/emit-typed-native-go.js +436 -1078
  44. package/dist/generator/emit-typed-native-go.js.map +1 -1
  45. package/dist/generator/emit-typed-native-rust.d.ts +9 -7
  46. package/dist/generator/emit-typed-native-rust.d.ts.map +1 -1
  47. package/dist/generator/emit-typed-native-rust.js +313 -844
  48. package/dist/generator/emit-typed-native-rust.js.map +1 -1
  49. package/dist/generator/typed.d.ts +4 -2
  50. package/dist/generator/typed.d.ts.map +1 -1
  51. package/dist/generator/typed.js +4 -2
  52. package/dist/generator/typed.js.map +1 -1
  53. package/package.json +12 -2
@@ -5,7 +5,20 @@ import { goTypedInternals } from "./emit-shared-go-typed.js";
5
5
  import { buildTypePlan, deriveTypeRef, findDecl, inputPortIsOptional, inputPortTypeRef } from "./typed.js";
6
6
  import { concurrencyPlan, execPlan, analyzeSequentialOps, classifyExpr, buildComponentPlan, } from "./straightline.js";
7
7
  import { NativeExprCompiler } from "./native-expr.js";
8
+ import { buildDeBoxPlan, notationOfRef } from "./emit-shared-debox.js";
8
9
  const PKG = "dslcontracts";
10
+ /** resolveGoWire — the CONCRETE consumer wire type names the de-box classifies a node result against
11
+ * (bc#141). Default (no option) → the in-package convention names, unqualified. A configured `import`
12
+ * qualifies the names with the imported package's selector so a consumer can keep its wire types in its
13
+ * own package. `value`/`row`/`list` name the WireValue / WireRow / WireList concrete types; the covered
14
+ * runner + the generated Probe result structs reference them by these names. */
15
+ function resolveGoWire(ctx) {
16
+ const w = ctx.goWire;
17
+ if (w === undefined)
18
+ return { value: "WireValue", row: "WireRow", list: "WireList" };
19
+ const sel = w.import !== undefined ? `${w.import.split("/").pop().replace(/[^A-Za-z0-9_]/g, "_")}.` : "";
20
+ return { value: `${sel}${w.value}`, row: `${sel}${w.row}`, list: `${sel}${w.list}`, import: w.import };
21
+ }
9
22
  /** goErr — build the LOCAL concrete error value for a behavior/plan failure on the covered read
10
23
  * plane (runtime-free). The covered module declares `type BehaviorError struct { Code, Message string }`
11
24
  * (see emitBehaviorErrorType); a `*BehaviorError` satisfies the runner's `error` return. This REPLACES
@@ -100,60 +113,184 @@ const { goFieldName, renderTypeRef, goScalar, serializeTyped, emitTypeDecls, emi
100
113
  function typedLocal(nodeId) {
101
114
  return `t_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
102
115
  }
103
- function recordTop(ref) {
104
- if (ref.kind === "named")
105
- return { kind: "named", innerName: ref.name };
106
- if (ref.kind === "arr" && ref.elem.kind === "named")
107
- return { kind: "arr", innerName: ref.elem.name };
108
- if (ref.kind === "opt" && ref.inner.kind === "named")
109
- return { kind: "opt", innerName: ref.inner.name };
110
- if (ref.kind === "map" && ref.value.kind === "named")
111
- return { kind: "map", innerName: ref.value.name };
112
- return null;
113
- }
114
- /** deBoxEligiblea componentRef node whose result is a record-containing top (named / arr(named) /
115
- * opt(named) / map(named)). Its handler returns the wire; the generated decode probes each record. */
116
- function deBoxEligible(ref) {
117
- return recordTop(ref) !== null;
118
- }
119
- /** goWireTypeForTop — the Go handler return type for a record-containing top's wire. */
120
- function goWireTypeForTop(top) {
121
- switch (top.kind) {
122
- case "named":
123
- return "WireRow";
124
- case "arr":
125
- return "[]WireRow";
126
- case "opt":
127
- return "WireRow"; // a nil WireRow = None (opt admits absent)
116
+ // ── strict de-box: the ONE inline renderer over the SSoT plan ─────────────────────────────
117
+ //
118
+ // A covered node result de-box is compiled INLINE at its consumption point from the language-neutral
119
+ // SSoT walk (emit-shared-debox.ts `buildDeBoxPlan`). The handler returns the consumer's WIRE (a single
120
+ // concrete WireValue the producer's datum); the generated de-box classifies it against the STATICALLY
121
+ // declared node type via the CONCRETE seam methods (WireValue.As* the top; WireRow.Probe* a record
122
+ // field / map value; WireList.Elem* → a list element). The consumer supplies variant classification (a
123
+ // probe reports the producer's own wire tag as a free string); the generated code owns strictness —
124
+ // required/optional, present/absent, error assembly, fail-closed. NO decodeWire_* helper, NO output-side
125
+ // recursion, NO interface, NO generics, NO boxed Value: a nested record expands to a nested struct
126
+ // build, a collection to a nested loop, and every method call resolves to a concrete consumer type.
127
+ /** goTypeOfPlanthe CONCRETE Go type of a de-box plan node (base kind + `optDepth` `*` wraps). Equal to
128
+ * renderTypeRef of the ORIGINAL ref, but read off the language-neutral plan so the inline renderer can
129
+ * declare its temps / list-element / map-value locals without re-deriving the TypeRef. */
130
+ function goTypeOfPlan(plan) {
131
+ let base;
132
+ switch (plan.k) {
133
+ case "scalar":
134
+ base = goScalar(plan.scalar);
135
+ break;
136
+ case "record":
137
+ base = plan.typeName;
138
+ break;
139
+ case "list":
140
+ base = `[]${goTypeOfPlan(plan.elem)}`;
141
+ break;
128
142
  case "map":
129
- return "map[string]WireRow";
143
+ base = `map[string]${goTypeOfPlan(plan.value)}`;
144
+ break;
130
145
  }
146
+ return "*".repeat(plan.optDepth) + base;
131
147
  }
132
- /** notationOfRef — the Portable Type Notation of a TypeRef (scp-error.md), resolving a named ref to its
133
- * obj notation via the plan. Baked as the `expectedType` literal: a rendering of the STATICALLY declared
134
- * type, so nothing walks a type at runtime. */
135
- function notationOfRef(ref, plan) {
136
- switch (ref.kind) {
137
- case "scalar":
138
- return ref.scalar;
139
- case "opt":
140
- return `opt(${notationOfRef(ref.inner, plan)})`;
141
- case "arr":
142
- return `arr(${notationOfRef(ref.elem, plan)})`;
143
- case "map":
144
- return `map(${notationOfRef(ref.value, plan)})`;
145
- case "named": {
146
- const decl = findDecl(plan, ref.name);
147
- return `obj{${decl.fields.map((f) => `${f.name}:${notationOfRef(f.type, plan)}`).join(",")}}`;
148
+ /**
149
+ * renderGoDeBox the ONE inline, recursive strict de-box renderer (Go). Folds a language-neutral
150
+ * {@link DeBoxPlan} (the SSoT walk) into FLAT Go STATEMENTS that decode the wire obtained by probing
151
+ * `srcExpr` per the node's access (top → `As*()`, field → `Probe*(key)`, elem → `Elem*(i)`, mapval →
152
+ * `Probe*(k)`) and assign the decoded native value into the lvalue `target`. The recursion runs HERE at
153
+ * generation time (walking the plan), so the emitted Go is fully unrolled: NO `decodeWire_*` helper, NO
154
+ * output-side recursion — a nested record expands to a nested struct build, a nested collection to a
155
+ * nested loop. A required-position mismatch runs `fail(...)` (default: `return <zero>, de_*(...)`); an
156
+ * optional position (optDepth>0) leaves the target pointer nil on absent/null. `ctr` hands out unique
157
+ * temp suffixes so nested blocks never collide; `idxExpr` is the element index / map-key argument the
158
+ * enclosing list / map loop supplies (empty for top / field). Mirrors the interpreter's outType check,
159
+ * but TOTAL over the grammar (opt(named)/arr(arr)/map(opt)…) and inlined — the type is baked all the way
160
+ * through by the TS compiler, and every seam call resolves to a CONCRETE consumer type (no dispatch).
161
+ */
162
+ function renderGoDeBox(plan, target, srcExpr, ctr, indent, fail, idxExpr = "") {
163
+ const I = indent;
164
+ const I1 = indent + "\t";
165
+ const I2 = indent + "\t\t";
166
+ const id = ctr.n++;
167
+ const ml = JSON.stringify(plan.model);
168
+ const fl = JSON.stringify(plan.field);
169
+ const nl = JSON.stringify(plan.expectedType);
170
+ const opt = plan.optDepth > 0;
171
+ const pv = `p${id}`;
172
+ const kindSuffix = plan.k === "list" ? "List" : plan.k === "scalar" ? (plan.scalar === "string" ? "String" : plan.scalar === "bool" ? "Bool" : "Number") : "Row";
173
+ // the probe call for this node's access (top → As*, field/mapval → Probe*(key), elem → Elem*(i)).
174
+ const probeCall = (() => {
175
+ switch (plan.access.from) {
176
+ case "top":
177
+ return `${srcExpr}.As${kindSuffix}()`;
178
+ case "field":
179
+ return `${srcExpr}.Probe${kindSuffix}(${JSON.stringify(plan.access.key)})`;
180
+ case "elem":
181
+ return `${srcExpr}.Elem${kindSuffix}(${idxExpr})`;
182
+ case "mapval":
183
+ return `${srcExpr}.Probe${kindSuffix}(${idxExpr})`;
148
184
  }
185
+ })();
186
+ const mismatch = fail(`deTypeMismatch(${ml}, ${fl}, ${nl}, ${pv}.ActualWireType, ${pv}.Raw)`);
187
+ const missing = fail(`deMissingField(${ml}, ${fl}, ${nl})`);
188
+ // wrap a decoded BASE-typed temp in optDepth `&` layers into target (present ⇒ &^N; absent/null ⇒ nil).
189
+ const wrapAssign = (baseTemp) => {
190
+ if (plan.optDepth === 0)
191
+ return [`${I1}${target} = ${baseTemp}`];
192
+ const out = [];
193
+ let cur = baseTemp;
194
+ for (let i = 0; i < plan.optDepth; i++) {
195
+ if (i === plan.optDepth - 1)
196
+ out.push(`${I1}${target} = &${cur}`);
197
+ else {
198
+ const w = `w${id}_${i}`;
199
+ out.push(`${I1}${w} := &${cur}`);
200
+ cur = w;
201
+ }
202
+ }
203
+ return out;
204
+ };
205
+ const lines = [];
206
+ lines.push(`${I}${pv} := ${probeCall}`);
207
+ lines.push(`${I}if ${pv}.Kind == probeGot {`);
208
+ if (plan.k === "scalar") {
209
+ if (plan.scalar === "string" || plan.scalar === "bool") {
210
+ if (plan.optDepth === 0)
211
+ lines.push(`${I1}${target} = ${pv}.Got`);
212
+ else {
213
+ lines.push(`${I1}sv${id} := ${pv}.Got`);
214
+ for (const l of wrapAssign(`sv${id}`))
215
+ lines.push(l);
216
+ }
217
+ }
218
+ else {
219
+ // int/float: parse + range-check here (BC owns overflow) — no panic, a structured overflow error.
220
+ const parse = plan.scalar === "int" ? `strconv.ParseInt(${pv}.Got, 10, 64)` : `strconv.ParseFloat(${pv}.Got, 64)`;
221
+ lines.push(`${I1}n${id}, nErr${id} := ${parse}`);
222
+ lines.push(`${I1}if nErr${id} != nil {`);
223
+ lines.push(`${I2}${fail(`deOverflow(${ml}, ${fl}, ${nl}, ${pv}.ActualWireType, ${pv}.Got)`)}`);
224
+ lines.push(`${I1}}`);
225
+ for (const l of wrapAssign(`n${id}`))
226
+ lines.push(l);
227
+ }
228
+ }
229
+ else if (plan.k === "record") {
230
+ lines.push(`${I1}var rec${id} ${plan.typeName}`);
231
+ for (const f of plan.fields)
232
+ lines.push(renderGoDeBox(f.plan, `rec${id}.${goFieldName(f.name)}`, `${pv}.Got`, ctr, I1, fail));
233
+ for (const l of wrapAssign(`rec${id}`))
234
+ lines.push(l);
149
235
  }
236
+ else if (plan.k === "list") {
237
+ const elemGo = goTypeOfPlan(plan.elem);
238
+ lines.push(`${I1}list${id} := make([]${elemGo}, 0, ${pv}.Got.Len())`);
239
+ lines.push(`${I1}for i${id} := 0; i${id} < ${pv}.Got.Len(); i${id}++ {`);
240
+ lines.push(`${I2}var el${id} ${elemGo}`);
241
+ lines.push(renderGoDeBox(plan.elem, `el${id}`, `${pv}.Got`, ctr, I2, fail, `i${id}`));
242
+ lines.push(`${I2}list${id} = append(list${id}, el${id})`);
243
+ lines.push(`${I1}}`);
244
+ for (const l of wrapAssign(`list${id}`))
245
+ lines.push(l);
246
+ }
247
+ else {
248
+ // map(V): the wire value is a producer map; enumerate its keys, decode each value as V.
249
+ const valGo = goTypeOfPlan(plan.value);
250
+ lines.push(`${I1}m${id} := make(map[string]${valGo})`);
251
+ lines.push(`${I1}for _, k${id} := range ${pv}.Got.Keys() {`);
252
+ lines.push(`${I2}var mv${id} ${valGo}`);
253
+ lines.push(renderGoDeBox(plan.value, `mv${id}`, `${pv}.Got`, ctr, I2, fail, `k${id}`));
254
+ lines.push(`${I2}m${id}[k${id}] = mv${id}`);
255
+ lines.push(`${I1}}`);
256
+ for (const l of wrapAssign(`m${id}`))
257
+ lines.push(l);
258
+ }
259
+ // WRONG → mismatch (required + optional). Required: NULL → mismatch, ABSENT → missing. Optional:
260
+ // NULL / ABSENT leave the target pointer nil (no statement — the zero value IS None).
261
+ lines.push(`${I}} else if ${pv}.Kind == probeWrong {`);
262
+ lines.push(`${I1}${mismatch}`);
263
+ if (!opt) {
264
+ lines.push(`${I}} else if ${pv}.Kind == probeNull {`);
265
+ lines.push(`${I1}${mismatch}`);
266
+ lines.push(`${I}} else {`);
267
+ lines.push(`${I1}${missing}`);
268
+ }
269
+ lines.push(`${I}}`);
270
+ return lines.join("\n");
150
271
  }
151
- /** emitProbeWireTypes — the once-per-module probe structs + WireRow/WireList seam interfaces. A
152
- * NumberProbe's Got is the raw numeric text (the de-box parses + range-checks it, so overflow is BC's
153
- * to detect); every probe carries ActualWireType even on a match so overflow can report the numeric
154
- * wire tag. Raw is the offending value stringified (NOT named RawValue that token is reserved for the
155
- * ErrorDetail field decl). Concrete structs / named interfaces no boxed Value on the seam. */
156
- function emitProbeWireTypes() {
272
+ /** returnZeroFail — the default de-box mismatch control flow: return the runner's zero output + the
273
+ * structured Error Value (fail/retry componentRef results + map/fanout element de-box, which fails closed
274
+ * regardless of elementPolicy matching the interpreter's whole-node outType throw). */
275
+ const returnZeroFail = (zeroOut) => (errValueExpr) => `return ${zeroOut}, ${errValueExpr}`;
276
+ /** renderResultDeBox inline strict de-box of a whole result WIRE (`srcExpr`, a WireValue) into the
277
+ * lvalue `target`, from the TOTAL SSoT plan for `ref` at the top position. `fail` selects the mismatch
278
+ * control flow. This is the ONE de-box call the runner arms share (componentRef result + map/fanout
279
+ * element) — no per-position predicate, no helper decode fn. `ctr` hands out unique temp suffixes: the
280
+ * sequential runner threads ONE counter across all its at-fn-scope nodes so siblings never collide;
281
+ * loop/if-scoped arms (map / fanout / parallel commit) may pass a fresh one. */
282
+ function renderResultDeBox(ref, target, srcExpr, nodeId, plan, indent, fail, ctr = { n: 0 }) {
283
+ return renderGoDeBox(buildDeBoxPlan(ref, { from: "top" }, { model: nodeId, field: nodeId, plan }), target, srcExpr, ctr, indent, fail);
284
+ }
285
+ /** emitProbeWireTypes — the once-per-module probe kind consts + probe RESULT structs. A NumberProbe's
286
+ * Got is the raw numeric text (the de-box parses + range-checks it, so overflow is BC's to detect); every
287
+ * probe carries ActualWireType even on a match so overflow can report the numeric wire tag. Raw is the
288
+ * offending value stringified (NOT named RawValue — that token is reserved for the ErrorDetail field
289
+ * decl). Concrete data structs — no boxed Value on the seam. bc does NOT declare the WireValue/WireRow/
290
+ * WireList seam types (that would own the wire format, and a Go interface is vtable dynamic dispatch); it
291
+ * REFERENCES the consumer's CONCRETE types by name (RowProbe.Got is a `${wire.row}`, ListProbe.Got a
292
+ * `${wire.list}`) and the runner calls their methods directly (zero dynamic dispatch, zero dictionary). */
293
+ function emitProbeWireTypes(wire) {
157
294
  return `// Probe kinds — the outcome of classifying one wire attribute against a declared field type.
158
295
  const (
159
296
  probeGot uint8 = 0 // present; the wire variant matches the declared type
@@ -187,232 +324,23 @@ type BoolProbe struct {
187
324
  Raw string
188
325
  }
189
326
 
190
- // RowProbe / ListProbe — a composite probe result: a nested WireRow (a DynamoDB "M") or WireList (an "L").
327
+ // RowProbe / ListProbe — a composite probe result: a nested wire map (a DynamoDB "M") or wire array (an
328
+ // "L"). Got is the consumer's CONCRETE ${wire.row} / ${wire.list} (a value type — no boxed Value, no
329
+ // interface); the inline de-box probes it directly.
191
330
  type RowProbe struct {
192
331
  Kind uint8
193
- Got WireRow
332
+ Got ${wire.row}
194
333
  ActualWireType string
195
334
  Raw string
196
335
  }
197
336
 
198
337
  type ListProbe struct {
199
338
  Kind uint8
200
- Got WireList
339
+ Got ${wire.list}
201
340
  ActualWireType string
202
341
  Raw string
203
- }
204
-
205
- // WireRow — the consumer's wire item, probed per declared field by the generated de-box. The consumer
206
- // implements it over its wire payload (a DynamoDB AttributeValue map) and classifies each attribute's
207
- // variant; the generated de-box owns strictness. No boxed Value, no dynamic accessor.
208
- type WireRow interface {
209
- // Keys reports the attribute keys present (the entries of a wire map / DynamoDB "M"); the de-box
210
- // iterates them to decode a declared map(V) field.
211
- Keys() []string
212
- ProbeString(field string) StringProbe
213
- ProbeNumber(field string) NumberProbe
214
- ProbeBool(field string) BoolProbe
215
- ProbeRow(field string) RowProbe
216
- ProbeList(field string) ListProbe
217
- }
218
-
219
- // WireList — a wire array (a DynamoDB "L"), probed per element by the generated de-box.
220
- type WireList interface {
221
- Len() int
222
- ElemString(i int) StringProbe
223
- ElemNumber(i int) NumberProbe
224
- ElemBool(i int) BoolProbe
225
- ElemRow(i int) RowProbe
226
- ElemList(i int) ListProbe
227
342
  }`;
228
343
  }
229
- /** goDecodeFnName — the decode function name for a named type (deduped across the module). */
230
- function goDecodeNamedName(name) {
231
- return `decodeWire_${name.replace(/[^A-Za-z0-9_]/g, "_")}`;
232
- }
233
- /**
234
- * emitDecodeNamed — emit (once, deduped) `decodeWire_<Name>(w WireRow) (<GoType>, error)` for a named
235
- * type: probe each declared field from the type SSoT, produce the structured error on a mismatch
236
- * (deTypeMismatch / deMissingField / deOverflow), and recurse into nested named / arr fields. `model`
237
- * is the declaring type name (scp-error.md `model`). Nested named types are emitted transitively.
238
- */
239
- function emitDecodeNamed(name, plan, emitted, out) {
240
- const fn = goDecodeNamedName(name);
241
- if (emitted.has(fn))
242
- return fn;
243
- emitted.add(fn);
244
- const goType = name; // a named TypeRef renders to its own Go type name.
245
- const decl = findDecl(plan, name);
246
- const lines = [];
247
- lines.push(`// ${fn} — the strict de-box for '${name}': probe each declared field, fail closed on a`);
248
- lines.push(`// wire mismatch with the structured Error Value (byte-equal codes to run_behavior).`);
249
- lines.push(`func ${fn}(w WireRow) (${goType}, error) {`);
250
- lines.push(`\tvar out ${goType}`);
251
- const ctr = { n: 0 };
252
- for (const f of decl.fields) {
253
- lines.push(emitDecodeValue(`out.${goFieldName(f.name)}`, f.type, "w", JSON.stringify(f.name), false, name, f.name, `${goType}{}`, plan, emitted, out, 1, ctr));
254
- }
255
- lines.push(`\treturn out, nil`);
256
- lines.push(`}`);
257
- out.push(lines.join("\n"));
258
- return fn;
259
- }
260
- /**
261
- * emitDecodeValue — the SINGLE recursive decode over the full TypeRef grammar (scalar / opt(scalar) /
262
- * named / arr / map). It decodes one value of `ref`, obtained by probing `wireVar` at `keyExpr`, and
263
- * assigns it into the lvalue `target`. Every nested position (an arr element, a map value, an obj field)
264
- * recurses through THIS function, so arbitrary nesting (map-of-map, arr-of-map, …) works by construction
265
- * — there is no depth-specific decoder to leave a gap. A mismatch produces the structured Error Value
266
- * (deTypeMismatch / deMissingField / deOverflow) and returns `retZero`; no panic, no boxed value.
267
- *
268
- * - `keyExpr` the Go probe key: a quoted literal `"title"` (obj field), a map-key var, or a list index.
269
- * - `isElem` probe a WireList element (Elem*, no absent — an index always exists) vs a WireRow field
270
- * / map key (Probe*, absent → missingField).
271
- * - `fieldRaw` the raw error `field` label (scp-error.md). `ctr` gives every temp a unique suffix.
272
- */
273
- function emitDecodeValue(target, ref, wireVar, keyExpr, isElem, model, fieldRaw, retZero, plan, emitted, out, indent, ctr) {
274
- const t = "\t".repeat(indent);
275
- const ml = JSON.stringify(model);
276
- const fl = JSON.stringify(fieldRaw);
277
- const notation = notationOfRef(ref, plan);
278
- const nl = JSON.stringify(notation);
279
- const id = `_${ctr.n++}`;
280
- const lines = [];
281
- const rowProbe = `${wireVar}.${isElem ? "ElemRow" : "ProbeRow"}(${keyExpr})`;
282
- const listProbe = `${wireVar}.${isElem ? "ElemList" : "ProbeList"}(${keyExpr})`;
283
- // an absent attribute is a missing REQUIRED field (a WireList index always exists → no absent check).
284
- const absent = (pv) => isElem ? "" : `${t}\tif ${pv}.Kind == probeAbsent {\n${t}\t\treturn ${retZero}, deMissingField(${ml}, ${fl}, ${nl})\n${t}\t}\n`;
285
- const mismatch = (pv, ind) => `${ind}return ${retZero}, deTypeMismatch(${ml}, ${fl}, ${nl}, ${pv}.ActualWireType, ${pv}.Raw)`;
286
- // opt(scalar): Absent / Null → leave the pointer nil (valid, no error); Wrong → mismatch; Got → &value.
287
- if (ref.kind === "opt" && ref.inner.kind === "scalar" && ref.inner.scalar !== "null") {
288
- const pv = `p${id}`;
289
- lines.push(`${t}{`);
290
- lines.push(`${t}\t${pv} := ${scalarProbeCall(wireVar, keyExpr, ref.inner.scalar, isElem).call}`);
291
- lines.push(`${t}\tif ${pv}.Kind == probeGot {`);
292
- lines.push(scalarAssignInto(target, pv, ref.inner.scalar, model, fieldRaw, notation, `${t}\t\t`, retZero, true));
293
- lines.push(`${t}\t} else if ${pv}.Kind == probeWrong {`);
294
- lines.push(mismatch(pv, `${t}\t\t`));
295
- lines.push(`${t}\t}`);
296
- lines.push(`${t}}`);
297
- return lines.join("\n");
298
- }
299
- if (ref.kind === "scalar" && ref.scalar !== "null") {
300
- const pv = `p${id}`;
301
- lines.push(`${t}{`);
302
- lines.push(`${t}\t${pv} := ${scalarProbeCall(wireVar, keyExpr, ref.scalar, isElem).call}`);
303
- if (!isElem)
304
- lines.push(absent(pv).replace(/\n$/, ""));
305
- lines.push(`${t}\tif ${pv}.Kind != probeGot {`); // Wrong or Null on a required value → mismatch
306
- lines.push(mismatch(pv, `${t}\t\t`));
307
- lines.push(`${t}\t}`);
308
- lines.push(scalarAssignInto(target, pv, ref.scalar, model, fieldRaw, notation, `${t}\t`, retZero, false));
309
- lines.push(`${t}}`);
310
- return lines.join("\n");
311
- }
312
- if (ref.kind === "named") {
313
- const dec = emitDecodeNamed(ref.name, plan, emitted, out);
314
- const rp = `r${id}`;
315
- lines.push(`${t}{`);
316
- lines.push(`${t}\t${rp} := ${rowProbe}`);
317
- if (!isElem)
318
- lines.push(absent(rp).replace(/\n$/, ""));
319
- lines.push(`${t}\tif ${rp}.Kind != probeGot {`);
320
- lines.push(mismatch(rp, `${t}\t\t`));
321
- lines.push(`${t}\t}`);
322
- lines.push(`${t}\tv${id}, e${id} := ${dec}(${rp}.Got)`);
323
- lines.push(`${t}\tif e${id} != nil {`);
324
- lines.push(`${t}\t\treturn ${retZero}, e${id}`);
325
- lines.push(`${t}\t}`);
326
- lines.push(`${t}\t${target} = v${id}`);
327
- lines.push(`${t}}`);
328
- return lines.join("\n");
329
- }
330
- if (ref.kind === "arr") {
331
- const lp = `l${id}`;
332
- const elemGo = renderTypeRef(ref.elem);
333
- lines.push(`${t}{`);
334
- lines.push(`${t}\t${lp} := ${listProbe}`);
335
- if (!isElem)
336
- lines.push(absent(lp).replace(/\n$/, ""));
337
- lines.push(`${t}\tif ${lp}.Kind != probeGot {`);
338
- lines.push(mismatch(lp, `${t}\t\t`));
339
- lines.push(`${t}\t}`);
340
- lines.push(`${t}\t${target} = make([]${elemGo}, 0, ${lp}.Got.Len())`);
341
- lines.push(`${t}\tfor i${id} := 0; i${id} < ${lp}.Got.Len(); i${id}++ {`);
342
- lines.push(`${t}\t\tvar el${id} ${elemGo}`);
343
- lines.push(emitDecodeValue(`el${id}`, ref.elem, `${lp}.Got`, `i${id}`, true, model, fieldRaw, retZero, plan, emitted, out, indent + 2, ctr));
344
- lines.push(`${t}\t\t${target} = append(${target}, el${id})`);
345
- lines.push(`${t}\t}`);
346
- lines.push(`${t}}`);
347
- return lines.join("\n");
348
- }
349
- if (ref.kind === "map") {
350
- // a declared map(V): the wire value is a producer map (a DynamoDB "M"); enumerate its keys and decode
351
- // each value as V through THIS same recursion (so map-of-map / map-of-arr nest by construction).
352
- const mp = `m${id}`;
353
- const valGo = renderTypeRef(ref.value);
354
- lines.push(`${t}{`);
355
- lines.push(`${t}\t${mp} := ${rowProbe}`);
356
- if (!isElem)
357
- lines.push(absent(mp).replace(/\n$/, ""));
358
- lines.push(`${t}\tif ${mp}.Kind != probeGot {`);
359
- lines.push(mismatch(mp, `${t}\t\t`));
360
- lines.push(`${t}\t}`);
361
- lines.push(`${t}\t${target} = make(map[string]${valGo})`);
362
- lines.push(`${t}\tfor _, k${id} := range ${mp}.Got.Keys() {`);
363
- lines.push(`${t}\t\tvar mv${id} ${valGo}`);
364
- lines.push(emitDecodeValue(`mv${id}`, ref.value, `${mp}.Got`, `k${id}`, false, model, fieldRaw, retZero, plan, emitted, out, indent + 2, ctr));
365
- lines.push(`${t}\t\t${target}[k${id}] = mv${id}`);
366
- lines.push(`${t}\t}`);
367
- lines.push(`${t}}`);
368
- return lines.join("\n");
369
- }
370
- // fail closed at generation for a shape the grammar does not cover (e.g. opt of a non-scalar).
371
- throw new GeneratorFailure("UNSUPPORTED_NODE_STRAIGHTLINE", `go strict de-box: '${fieldRaw}' of '${model}' has type ${JSON.stringify(ref)} which the generated de-box does not decode (supported: scalar / opt(scalar) / named / arr / map).`);
372
- }
373
- /** scalarProbeCall — the probe method call for a scalar of the given kind (string→ProbeString/ElemString,
374
- * int|float→ProbeNumber/ElemNumber, bool→ProbeBool/ElemBool). `keyOrIndex` is a quoted key (row) or an
375
- * index var (list). */
376
- function scalarProbeCall(wireVar, keyOrIndex, scalar, isElem) {
377
- const m = scalar === "string" ? "String" : scalar === "bool" ? "Bool" : "Number";
378
- const method = (isElem ? "Elem" : "Probe") + m;
379
- return { call: `${wireVar}.${method}(${keyOrIndex})` };
380
- }
381
- /** scalarAssignInto — assign a probeGot scalar into an lvalue `target` (opt → pointer). Number is parsed
382
- * + range-checked here (BC owns overflow). No panic on parse failure — a structured overflow error. The
383
- * `n/nErr/f/fErr/v` temps are safe because every scalar decode is wrapped in its own `{ }` block. */
384
- function scalarAssignInto(fieldExpr, pv, scalar, model, key, notation, t, retZero, asPtr) {
385
- const ml = JSON.stringify(model);
386
- const kl = JSON.stringify(key);
387
- const nl = JSON.stringify(notation);
388
- if (scalar === "string") {
389
- return asPtr ? `${t}v := ${pv}.Got\n${t}${fieldExpr} = &v` : `${t}${fieldExpr} = ${pv}.Got`;
390
- }
391
- if (scalar === "bool") {
392
- return asPtr ? `${t}v := ${pv}.Got\n${t}${fieldExpr} = &v` : `${t}${fieldExpr} = ${pv}.Got`;
393
- }
394
- if (scalar === "int") {
395
- const l = [];
396
- l.push(`${t}n, nErr := strconv.ParseInt(${pv}.Got, 10, 64)`);
397
- l.push(`${t}if nErr != nil {`);
398
- l.push(`${t}\treturn ${retZero}, deOverflow(${ml}, ${kl}, ${nl}, ${pv}.ActualWireType, ${pv}.Got)`);
399
- l.push(`${t}}`);
400
- l.push(asPtr ? `${t}${fieldExpr} = &n` : `${t}${fieldExpr} = n`);
401
- return l.join("\n");
402
- }
403
- // float — int widens to float; a non-numeric raw is a range/parse failure (overflow kind).
404
- const l = [];
405
- l.push(`${t}f, fErr := strconv.ParseFloat(${pv}.Got, 64)`);
406
- l.push(`${t}if fErr != nil {`);
407
- l.push(`${t}\treturn ${retZero}, deOverflow(${ml}, ${kl}, ${nl}, ${pv}.ActualWireType, ${pv}.Got)`);
408
- l.push(`${t}}`);
409
- l.push(asPtr ? `${t}${fieldExpr} = &f` : `${t}${fieldExpr} = f`);
410
- return l.join("\n");
411
- }
412
- /** goDecodeElemName — the element de-box function name for a map/fanout node (per node). */
413
- function goDecodeElemName(compName, nodeId) {
414
- return `decodeWireElem_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
415
- }
416
344
  /** mapFanoutElemRef — the element ROW TypeRef a map/fanout node decodes (the per-element record). */
417
345
  function mapFanoutElemRef(node, typedNodes, plan) {
418
346
  const ref = typedNodes.get(node.id);
@@ -420,190 +348,6 @@ function mapFanoutElemRef(node, typedNodes, plan) {
420
348
  return fanoutItemsElemRef(node, ref, plan);
421
349
  return mapElemRowRef(node, ref, plan);
422
350
  }
423
- /** mapFanoutElemDeBoxEligible — a map/fanout node whose element ROW is a named record de-boxes each
424
- * element through the generated decodeWireElem_* (closing the scan-row silent-default hole). */
425
- function mapFanoutElemDeBoxEligible(node, typedNodes, plan) {
426
- return mapFanoutElemRef(node, typedNodes, plan).kind === "named";
427
- }
428
- /**
429
- * emitDecodeElemRow — emit (once) `decodeWireElem_<comp>_<node>(w WireRow) (RawElem_<comp>_<node>, error)`
430
- * for a map/fanout node whose element ROW is a named record: probe each declared field via the SAME
431
- * recursion as record reads (emitDecodeValue) and build the concrete RawElem struct, failing closed with
432
- * the structured Error Value on a mismatch. This is the componentRef seam extended to scan/fan-out rows.
433
- */
434
- function emitDecodeElemRow(comp, node, elemRowRef, plan, emitted, out) {
435
- const nodeId = node.id;
436
- const fn = goDecodeElemName(comp.name, nodeId);
437
- if (emitted.has(fn))
438
- return fn;
439
- emitted.add(fn);
440
- const retType = rawElemStructName(comp.name, nodeId);
441
- const decl = findDecl(plan, elemRowRef.name);
442
- const lines = [];
443
- lines.push(`// ${fn} — the strict de-box for a '${nodeId}' element row: probe each declared field, fail`);
444
- lines.push(`// closed on a wire mismatch with the structured Error Value (byte-equal codes to run_behavior).`);
445
- lines.push(`func ${fn}(w WireRow) (${retType}, error) {`);
446
- lines.push(`\tvar out ${retType}`);
447
- const ctr = { n: 0 };
448
- for (const f of decl.fields) {
449
- lines.push(emitDecodeValue(`out.${goFieldName(f.name)}`, f.type, "w", JSON.stringify(f.name), false, elemRowRef.name, f.name, `${retType}{}`, plan, emitted, out, 1, ctr));
450
- }
451
- lines.push(`\treturn out, nil`);
452
- lines.push(`}`);
453
- out.push(lines.join("\n"));
454
- return fn;
455
- }
456
- /** emitNodeDecodeFns — emit the decode functions for every de-box-eligible node in a component: a
457
- * componentRef record read (decodeWire_<Name>) OR a map/fanout element row (decodeWireElem_<comp>_<node>).
458
- * Deduped; nested named fields recurse through the shared decodeWire_<Name>. */
459
- /** goDecodeResultName — the top-result decode function name for a de-box componentRef node. */
460
- function goDecodeResultName(compName, nodeId) {
461
- return `decodeWireResult_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
462
- }
463
- /**
464
- * emitDecodeWireResult — emit (once) `decodeWireResult_<comp>_<node>(wire <WireType>) (<ResultType>,
465
- * error)` for a componentRef node whose result is a record-containing top: it decodes each record via
466
- * decodeWire_<InnerName> and assembles the top (a record / []record / *record / map[string]record),
467
- * failing closed with the structured Error Value on a mismatch. This is the SAME decode recursion at the
468
- * node-result position — one path covers named / arr(named) / opt(named) / map(named).
469
- */
470
- function emitDecodeWireResult(comp, node, ref, plan, emitted, out) {
471
- const top = recordTop(ref);
472
- const fn = goDecodeResultName(comp.name, node.id);
473
- if (emitted.has(fn))
474
- return fn;
475
- emitted.add(fn);
476
- const innerDecode = emitDecodeNamed(top.innerName, plan, emitted, out);
477
- const resultType = renderTypeRef(ref);
478
- const wireType = goWireTypeForTop(top);
479
- const lines = [];
480
- lines.push(`// ${fn} — decode the node's record-containing '${top.kind}' result from the wire (each record`);
481
- lines.push(`// via ${innerDecode}); a de-box mismatch fails closed with the structured Error Value.`);
482
- lines.push(`func ${fn}(wire ${wireType}) (${resultType}, error) {`);
483
- switch (top.kind) {
484
- case "named":
485
- lines.push(`\treturn ${innerDecode}(wire)`);
486
- break;
487
- case "arr":
488
- lines.push(`\tout := make(${resultType}, 0, len(wire))`);
489
- lines.push(`\tfor _, w := range wire {`);
490
- lines.push(`\t\te, err := ${innerDecode}(w)`);
491
- lines.push(`\t\tif err != nil {`, `\t\t\treturn nil, err`, `\t\t}`);
492
- lines.push(`\t\tout = append(out, e)`);
493
- lines.push(`\t}`);
494
- lines.push(`\treturn out, nil`);
495
- break;
496
- case "opt":
497
- lines.push(`\tif wire == nil {`, `\t\treturn nil, nil`, `\t}`);
498
- lines.push(`\tr, err := ${innerDecode}(wire)`);
499
- lines.push(`\tif err != nil {`, `\t\treturn nil, err`, `\t}`);
500
- lines.push(`\treturn &r, nil`);
501
- break;
502
- case "map":
503
- lines.push(`\tout := make(${resultType})`);
504
- lines.push(`\tfor k, w := range wire {`);
505
- lines.push(`\t\tr, err := ${innerDecode}(w)`);
506
- lines.push(`\t\tif err != nil {`, `\t\t\treturn nil, err`, `\t\t}`);
507
- lines.push(`\t\tout[k] = r`);
508
- lines.push(`\t}`);
509
- lines.push(`\treturn out, nil`);
510
- break;
511
- }
512
- lines.push(`}`);
513
- out.push(lines.join("\n"));
514
- return fn;
515
- }
516
- function emitNodeDecodeFns(comp, typedNodes, plan, emitted, out) {
517
- for (const n of comp.body) {
518
- if ("cond" in n)
519
- continue;
520
- if ("map" in n || "fanout" in n) {
521
- const node = n;
522
- if (!mapFanoutElemDeBoxEligible(node, typedNodes, plan))
523
- continue;
524
- emitDecodeElemRow(comp, node, mapFanoutElemRef(node, typedNodes, plan), plan, emitted, out);
525
- continue;
526
- }
527
- const ref = typedNodes.get(n.id);
528
- if (ref === undefined)
529
- continue;
530
- const top = recordTop(ref);
531
- if (top === null)
532
- continue;
533
- // a NAMED top decodes in place via decodeWire_<Name>; an arr/opt/map top assembles via
534
- // decodeWireResult_* (which itself recurses into decodeWire_<Name> per record).
535
- if (top.kind === "named")
536
- emitDecodeNamed(top.innerName, plan, emitted, out);
537
- else
538
- emitDecodeWireResult(comp, n, ref, plan, emitted, out);
539
- }
540
- }
541
- /** containsNamed — whether a TypeRef transitively contains a named record (through arr / opt / map). */
542
- function containsNamed(ref) {
543
- switch (ref.kind) {
544
- case "scalar":
545
- return false;
546
- case "named":
547
- return true;
548
- case "opt":
549
- return containsNamed(ref.inner);
550
- case "arr":
551
- return containsNamed(ref.elem);
552
- case "map":
553
- return containsNamed(ref.value);
554
- }
555
- }
556
- /** readsAPriorNode — a componentRef node is a DATAFLOW consumer iff at least one input port is a ref
557
- * headed by a PRIOR BODY NODE (it reads a prior node's already-native result, #129), rather than a fresh
558
- * external wire read whose ports come from input params / static / an element ($as) binding. This is the
559
- * same head-is-a-body-node signal priorNodeArrElemInfo (#129) uses to lower a prior-node array feed. */
560
- function readsAPriorNode(node, typedNodes) {
561
- for (const expr of Object.values(node.ports ?? {})) {
562
- const e = classifyExpr(expr);
563
- if (e.kind === "ref" && e.path.length >= 1 && typedNodes.has(e.path[0]))
564
- return true;
565
- }
566
- return false;
567
- }
568
- /**
569
- * assertDeBoxableResults — fail closed (never a silent trust) for a covered node whose result would
570
- * materialize on the trusting typed path and silently default a wrong wire value. Two shapes fail closed:
571
- * (1) a NON-named top (arr / opt / map) that transitively contains a record the de-box does not decode
572
- * (deeper nesting like arr(arr(named))) — it would trust the record's wire fields; (2) a HANDLER-BACKED
573
- * componentRef node whose result is a pure scalar / scalar-collection top (arr(scalar) / opt(scalar) /
574
- * map(scalar) / bare scalar) — it materializes `t = row.Val` on the trusting path, so a wrong wire value
575
- * silently defaults (diverging from run_behavior's outType check). Either is a loud generation-time error
576
- * (native-codegen-standard §2 — an unsupported shape fails closed, never escapes to a trusting path). A
577
- * record top (de-boxed) and a DATAFLOW scalar top (a prior-node-fed result, computed from already-native
578
- * data — #129 folds) both generate.
579
- */
580
- function assertDeBoxableResults(comp, typedNodes, plan) {
581
- for (const n of comp.body) {
582
- if ("cond" in n)
583
- continue;
584
- const isMapFanout = "map" in n || "fanout" in n;
585
- const ref = isMapFanout ? mapFanoutElemRef(n, typedNodes, plan) : typedNodes.get(n.id);
586
- const deBoxed = isMapFanout ? ref.kind === "named" : recordTop(ref) !== null;
587
- if (deBoxed)
588
- continue;
589
- const nodeId = n.id;
590
- if (containsNamed(ref)) {
591
- throw new GeneratorFailure("UNSUPPORTED_NODE_STRAIGHTLINE", `go strict de-box: node '${nodeId}' shape ${JSON.stringify(ref)} contains a record the de-box does not decode (a deeper nesting than a direct named / arr / opt / map of a named record). It would trust the record's wire fields (silent default) — the silent-default red line forbids. Fail closed: reshape so the record is a direct de-box top, or extend the recursion for this nesting.`);
592
- }
593
- // a map/fanout element is ALWAYS a per-element wire read; only a named record is de-boxed
594
- // (decodeWireElem_*). A scalar / scalar-collection element materializes from the trusting per-element
595
- // `.Val` — a wrong wire value silent-defaults. Fail closed.
596
- if (isMapFanout) {
597
- throw new GeneratorFailure("UNSUPPORTED_NODE_STRAIGHTLINE", `go strict de-box: map/fanout node '${nodeId}' element ${JSON.stringify(ref)} is a scalar / scalar-collection per-element wire read that materializes on the trusting typed path — a wrong wire value would silent-default (diverging from run_behavior's outType check). Fail closed: declare the element as a record (de-boxed).`);
598
- }
599
- // a pure-scalar / scalar-collection top on a HANDLER-BACKED componentRef wire read trusts `t = row.Val`
600
- // (a wrong wire value silent-defaults). A DATAFLOW consumer (a port fed by a prior node) computes from
601
- // already-native data and generates.
602
- if (!readsAPriorNode(n, typedNodes)) {
603
- throw new GeneratorFailure("UNSUPPORTED_NODE_STRAIGHTLINE", `go strict de-box: node '${nodeId}' result top ${JSON.stringify(ref)} is a handler-backed scalar / scalar-collection read that materializes on the trusting typed path — a wrong wire value would silent-default (diverging from run_behavior's outType check). Fail closed: declare the result as a record (de-boxed) or feed it as dataflow from a prior node.`);
604
- }
605
- }
606
- }
607
351
  function goPortFieldName(wire) {
608
352
  const safe = wire.replace(/[^A-Za-z0-9_]/g, "_");
609
353
  const head = safe.charAt(0);
@@ -1050,32 +794,11 @@ type ${structName} struct {
1050
794
  ${fields}
1051
795
  }`;
1052
796
  }
1053
- // ── CONCRETE per-node row structs + row→outType copiers (bc: full Go concreteness) ──────────
1054
- //
1055
- // The covered path no longer crosses a generic `RawValue`/`RawRow` on the RESULT plane. Each
1056
- // covered node has a CONCRETE row struct `RawRow_<comp>_<node>` whose fields are the node's
1057
- // projected outType fields (typed, flattened). A row models a SUCCESS; failure travels the (T,
1058
- // per-component `Handler_<comp>` interface has one method per node returning that concrete struct;
1059
- // the runner reads `row.<Field>` DIRECTLY (no `.(RawRow)`, no `.(scalar)`, no `RawValue`) and copies
1060
- // each field into the node's outType struct local. The `.(T)` type-assert seam that the generic
1061
- // RawValue de-box carried is GONE on the covered path (the handler produces the typed fields).
1062
- //
1063
- // A scalar/arr/opt node (outType not a named struct) has a single `Val <typed>` payload field. A
1064
- // named-struct node has one Go field per outType field (same names/types as the outType decl), so
1065
- // `RawRow_<comp>_<node>` is structurally the outType struct. The copier is then a
1066
- // mechanical field-for-field assignment into the outType struct — NO dynamic value read anywhere.
1067
- /** Row_<comp>_<node> — the concrete per-node handler-result row struct name. (Deliberately NOT
1068
- * prefixed with the generic dynamic-accessor name — that accessor is what the concrete path removes.) */
1069
- function rawRowStructName(compName, nodeId) {
1070
- return `Row_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
1071
- }
1072
- /** RowElem_<comp>_<node> — the concrete per-ELEMENT row struct name for a covered map node (the
1073
- * element/into row the map handler yields per over element). */
1074
- function rawElemStructName(compName, nodeId) {
1075
- return `RowElem_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
1076
- }
1077
- /** Handler_<comp> — the per-component concrete handler interface name (one Node_* method per node). */
1078
- function handlerIfaceName(compName) {
797
+ /** handlerTypeName the per-component CONCRETE handler type name the runner takes by value (one Node_*
798
+ * method per node). It is NOT a bc-declared interface (a Go interface is vtable dynamic dispatch): the
799
+ * consumer supplies a concrete type of this name (default `Handler_<comp>`) and the runner calls
800
+ * `h.Node_*(...)` directly (zero dynamic dispatch, zero dictionary). */
801
+ function handlerTypeName(compName) {
1079
802
  return `Handler_${sanitize(compName)}`;
1080
803
  }
1081
804
  /** RunNativeRawStruct_<comp> — the EXPORTED name of the per-component struct-returning combined runner
@@ -1090,74 +813,6 @@ function runnerName(compName) {
1090
813
  function nodeMethodName(compName, nodeId) {
1091
814
  return `Node_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
1092
815
  }
1093
- /**
1094
- * emitRawRowStructs — emit the concrete `RawRow_<comp>_<node>` struct per covered node (and, for a
1095
- * covered map node, the per-element `RawElem_<comp>_<node>`). A named-struct outType flattens to one
1096
- * Go field per outType field; a scalar/arr/opt node carries a single `Val` payload. Every row carries
1097
- * A row models a SUCCESS; failure is the second (error) return, so no in-band error signal.
1098
- */
1099
- function emitRawRowStructs(comp, typedNodes, plan) {
1100
- const parts = [];
1101
- for (const n of comp.body) {
1102
- // #108: a cond node has NO handler-result row (pure Expression — no dispatch).
1103
- if ("cond" in n)
1104
- continue;
1105
- const ref = typedNodes.get(n.id);
1106
- if ("fanout" in n) {
1107
- // a covered fanout node: RawElem_ is the connection items element (the per-body row the batched
1108
- // handler yields, aligned to the deduped id list); the batch RawRow_ carries the aligned []RawElem_.
1109
- const elemRowRef = fanoutItemsElemRef(n, ref, plan);
1110
- parts.push(emitOneRowStruct(rawElemStructName(comp.name, n.id), elemRowRef, plan));
1111
- parts.push(`// ${rawRowStructName(comp.name, n.id)} — the BATCH row for fanout '${n.id}': the aligned per-body rows.\n` +
1112
- `type ${rawRowStructName(comp.name, n.id)} struct {\n\tRows []${rawElemStructName(comp.name, n.id)}\n}`);
1113
- continue;
1114
- }
1115
- if ("map" in n) {
1116
- // a covered map node: RawElem_<comp>_<node> is the HANDLER'S per-element return shape:
1117
- // - into: the `into` field's type (the fetched item merged onto every over element);
1118
- // - no-into (#93 shape 3): the element outType directly (connection-collect).
1119
- // The batched Node_* returns RawRow_<comp>_<node> (aligned []RawElem_ + error); a per-element
1120
- // dispatch Node_* returns RawElem_ directly (one physical call per element).
1121
- const arrRef = ref;
1122
- const elemRowRef = mapElemRowRef(n, arrRef, plan);
1123
- parts.push(emitOneRowStruct(rawElemStructName(comp.name, n.id), elemRowRef, plan));
1124
- parts.push(`// ${rawRowStructName(comp.name, n.id)} — the BATCH row for map '${n.id}': the aligned per-element rows.\n` +
1125
- `type ${rawRowStructName(comp.name, n.id)} struct {\n\tRows []${rawElemStructName(comp.name, n.id)}\n}`);
1126
- continue;
1127
- }
1128
- parts.push(emitOneRowStruct(rawRowStructName(comp.name, n.id), ref, plan));
1129
- }
1130
- return parts.join("\n\n");
1131
- }
1132
- /** Emit one concrete row struct: flatten a named outType to typed fields, else a single Val payload;
1133
- * A row models a SUCCESS; a failure is the second (error) return, so no in-band error signal. */
1134
- function emitOneRowStruct(name, ref, plan) {
1135
- const lines = [];
1136
- lines.push(`// ${name} — CONCRETE handler-result row (typed fields = the node's outType).`);
1137
- lines.push(`type ${name} struct {`);
1138
- if (ref.kind === "named") {
1139
- const decl = findDecl(plan, ref.name);
1140
- for (const f of decl.fields) {
1141
- lines.push(`\t${goFieldName(f.name)} ${renderTypeRef(f.type)} // ${JSON.stringify(f.name)}`);
1142
- }
1143
- }
1144
- else {
1145
- lines.push(`\tVal ${renderTypeRef(ref)}`);
1146
- }
1147
- lines.push(`}`);
1148
- return lines.join("\n");
1149
- }
1150
- /** emitRowCopy — the statements copying a concrete row's typed fields into the node's outType local
1151
- * `target` (a value of Go type renderTypeRef(ref)). Named: field-for-field; scalar/arr/opt: `.Val`.
1152
- * `rowExpr` is the concrete RawRow_/RawElem_ value; `indent` tabs. No dynamic read — pure assignment. */
1153
- function emitRowCopy(target, rowExpr, ref, plan, indent) {
1154
- const t = "\t".repeat(indent);
1155
- if (ref.kind === "named") {
1156
- const decl = findDecl(plan, ref.name);
1157
- return decl.fields.map((f) => `${t}${target}.${goFieldName(f.name)} = ${rowExpr}.${goFieldName(f.name)}`).join("\n");
1158
- }
1159
- return `${t}${target} = ${rowExpr}.Val`;
1160
- }
1161
816
  /**
1162
817
  * boundGoType (change #3 — typed `bound`) — the CONCRETE Go type of a covered node's `bound` handler
1163
818
  * param (bc#90 / runtime-free). `bound` is the parent-produced key (the bindField value); it replaces
@@ -1187,58 +842,6 @@ function boundGoType(node, comp, typedNodes, plan) {
1187
842
  return `*${renderTypeRef(bfRef.inner)}`;
1188
843
  return `*${renderTypeRef(bfRef)}`;
1189
844
  }
1190
- /**
1191
- * emitHandlerInterface — the per-component `Handler_<comp>` interface: one concrete-typed `Node_*`
1192
- * method per covered node. Each componentRef node method takes the node's native ports struct + the
1193
- * typed `bound` pointer (change #3 — the produced-aware parent key; NO boxed dslcontracts.Value) and
1194
- * returns its concrete row struct + a resolved bool. A covered map node's method takes the batch
1195
- * ports struct (batched) or the element ports struct (per-element) and returns the batch / element
1196
- * row. This is the fully-concrete, runtime-free replacement for the generic ExecNativeRaw seam.
1197
- */
1198
- function emitHandlerInterface(comp, typedNodes, plan) {
1199
- const lines = [];
1200
- lines.push(`// ${handlerIfaceName(comp.name)} — the CONCRETE per-component handler seam: one typed method`);
1201
- lines.push(`// per covered node (native ports struct IN, concrete row struct OUT). No generic boxed-ports`);
1202
- lines.push(`// / boxed-value / dynamic accessor crosses the covered boundary — the consumer implements each`);
1203
- lines.push(`// Node_* with a decode of its own wire payload into the concrete row (see INTEGRATION.md §6).`);
1204
- lines.push(`type ${handlerIfaceName(comp.name)} interface {`);
1205
- for (const n of comp.body) {
1206
- if ("cond" in n)
1207
- continue; // #108: a cond node has no handler method (pure Expression).
1208
- const method = nodeMethodName(comp.name, n.id);
1209
- const bt = boundGoType(n, comp, typedNodes, plan);
1210
- if ("fanout" in n) {
1211
- // fanout (v3): one batched dispatch of the deduped id list. Ports = the batch struct; returns the
1212
- // aligned per-body element WIRES ([]WireRow) that the runner de-boxes (decodeWireElem_*) then
1213
- // applies dedupe/drop/wrap to. A non-record element keeps its concrete batch-row return.
1214
- const portsT = `${portsStructName(comp.name, n.id)}_batch`;
1215
- const elemDeBox = mapFanoutElemDeBoxEligible(n, typedNodes, plan);
1216
- const retT = elemDeBox ? "[]WireRow" : rawRowStructName(comp.name, n.id);
1217
- lines.push(`\t${method}(ports ${portsT}, bound ${bt}) (${retT}, error)`);
1218
- continue;
1219
- }
1220
- if ("map" in n) {
1221
- const m = n.map;
1222
- const batched = m.batched === true;
1223
- const portsT = batched ? `${portsStructName(comp.name, n.id)}_batch` : portsStructName(comp.name, n.id);
1224
- // a record-element map returns the element WIRE(s) the runner de-boxes: batched → []WireRow (aligned
1225
- // to items), nonbatched → one WireRow per dispatch. A non-record element keeps its concrete row.
1226
- const elemDeBox = mapFanoutElemDeBoxEligible(n, typedNodes, plan);
1227
- const retT = elemDeBox ? (batched ? "[]WireRow" : "WireRow") : batched ? rawRowStructName(comp.name, n.id) : rawElemStructName(comp.name, n.id);
1228
- lines.push(`\t${method}(ports ${portsT}, bound ${bt}) (${retT}, error)`);
1229
- continue;
1230
- }
1231
- // a componentRef whose result is a record-containing top returns the wire (WireRow / []WireRow /
1232
- // nilable WireRow / map[string]WireRow); the generated de-box (decodeWireResult_*) probes each record
1233
- // strictly. A pure-scalar top (arr(scalar)/opt(scalar)/…) keeps its concrete row for direct copy.
1234
- const ref = typedNodes.get(n.id);
1235
- const top = ref !== undefined ? recordTop(ref) : null;
1236
- const retT = top !== null ? goWireTypeForTop(top) : rawRowStructName(comp.name, n.id);
1237
- lines.push(`\t${method}(ports ${portsStructName(comp.name, n.id)}, bound ${bt}) (${retT}, error)`);
1238
- }
1239
- lines.push(`}`);
1240
- return lines.join("\n");
1241
- }
1242
845
  /** mapElemMaterializerName — the augmented-element copier for a covered map...into node. */
1243
846
  function mapElemMaterializerName(compName, nodeId) {
1244
847
  return `materializeMapElemNR_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}`;
@@ -1351,9 +954,8 @@ function mapElemRowRef(node, arrRef, plan) {
1351
954
  }
1352
955
  /**
1353
956
  * emitMapElemMaterializers — for each covered map...into node, emit the AUGMENTED-element copier: copy
1354
- * the over element's typed fields + assign the `into` field from the concrete per-element handler row
1355
- * (RawElem_<comp>_<node>). Pure struct field assignment — NO dynamic value read (the handler already
1356
- * produced the typed into row).
957
+ * the over element's typed fields + place the already-de-boxed `into` value into its field. Pure struct
958
+ * field assignment — NO dynamic value read (the inline de-box already produced the typed `into` value).
1357
959
  */
1358
960
  function emitMapElemMaterializers(comp, typedNodes, plan) {
1359
961
  const parts = [];
@@ -1375,16 +977,15 @@ function emitMapElemMaterializers(comp, typedNodes, plan) {
1375
977
  const intoRowRef = mapElemRowRef(n, arrRef, plan);
1376
978
  const fn = mapElemMaterializerName(comp.name, n.id);
1377
979
  const overElemGo = mapOverElemType(comp, n, typedNodes, plan);
1378
- const elemRowGo = rawElemStructName(comp.name, n.id);
1379
980
  const lines = [];
1380
981
  lines.push(`// ${fn} — assemble the augmented map element '${n.id}': copy the over element's typed`);
1381
- lines.push(`// fields + set the '${intoKey}' (into) field from the concrete per-element handler row.`);
1382
- lines.push(`func ${fn}(over ${overElemGo}, into ${elemRowGo}) ${elemRef.name} {`);
982
+ lines.push(`// fields + set the '${intoKey}' (into) field from the already-de-boxed into value.`);
983
+ lines.push(`func ${fn}(over ${overElemGo}, into ${renderTypeRef(intoRowRef)}) ${elemRef.name} {`);
1383
984
  lines.push(`\tvar out ${elemRef.name}`);
1384
985
  for (const f of overFields) {
1385
986
  lines.push(`\tout.${goFieldName(f.name)} = over.${goFieldName(f.name)}`);
1386
987
  }
1387
- lines.push(emitRowCopy(`out.${goFieldName(intoKey)}`, "into", intoRowRef, plan, 1));
988
+ lines.push(`\tout.${goFieldName(intoKey)} = into`);
1388
989
  lines.push(`\treturn out`);
1389
990
  lines.push(`}`);
1390
991
  parts.push(lines.join("\n"));
@@ -1634,7 +1235,7 @@ function emitPortInit(pn, expr, comp, plan, typedNodes, isPrior, opts) {
1634
1235
  *
1635
1236
  * NO RunPlan / []OpSpec / planSpec walk: the staging, the bound, and which ops are parallel are baked.
1636
1237
  */
1637
- function emitParallelStageArm(comp, stage, atPos, concurrency, metas, typedNodes, plan, priorNodeAt, zeroOut, flags) {
1238
+ function emitParallelStageArm(comp, stage, atPos, concurrency, metas, typedNodes, plan, priorNodeAt, zeroOut, flags, wire) {
1638
1239
  const lines = [];
1639
1240
  const ids = stage.map((i) => comp.body[i].id);
1640
1241
  lines.push(`\t// ── bc#87 real-concurrency stage {${ids.map((x) => JSON.stringify(x)).join(", ")}} — static parallel`);
@@ -1671,16 +1272,9 @@ function emitParallelStageArm(comp, stage, atPos, concurrency, metas, typedNodes
1671
1272
  const node = comp.body[i];
1672
1273
  const s = sanitize(node.id);
1673
1274
  const structName = portsStructName(comp.name, comp.body[i].id);
1674
- const memRef = typedNodes.get(comp.body[i].id);
1675
- // a de-box member's goroutine returns the top's wire (WireRow / []WireRow / nilable WireRow /
1676
- // map[string]WireRow, decoded in COMMIT); a non-de-box member returns its concrete row directly.
1677
- const memTop = recordTop(memRef);
1678
- if (memTop !== null) {
1679
- lines.push(`\t\tvar wire_${s} ${goWireTypeForTop(memTop)}`);
1680
- }
1681
- else {
1682
- lines.push(`\t\tvar row_${s} ${rawRowStructName(comp.name, comp.body[i].id)}`);
1683
- }
1275
+ // every member's goroutine returns the result WIRE (a single WireValue); the ascending COMMIT phase
1276
+ // de-boxes it INLINE (so the wire not the decode is what the goroutine writes to its slot).
1277
+ lines.push(`\t\tvar wire_${s} ${wire.value}`);
1684
1278
  lines.push(`\t\tvar row_${s}Err error`);
1685
1279
  lines.push(`\t\trun_${s} := false`);
1686
1280
  lines.push(`\t\tvar ps_${s} ${structName}`);
@@ -1753,66 +1347,43 @@ function emitParallelStageArm(comp, stage, atPos, concurrency, metas, typedNodes
1753
1347
  lines.push(`\t\t\t\tdefer wg.Done()`);
1754
1348
  lines.push(`\t\t\t\tdefer func() { <-sem }()`);
1755
1349
  const boundArg = node.bindField !== undefined ? `bound_${s}` : "nil";
1756
- const resultVar = deBoxEligible(typedNodes.get(node.id)) ? `wire_${s}` : `row_${s}`;
1757
- lines.push(`\t\t\t\t${resultVar}, row_${s}Err = handlers.${nodeMethodName(comp.name, node.id)}(ps_${s}, ${boundArg})`);
1350
+ lines.push(`\t\t\t\twire_${s}, row_${s}Err = handlers.${nodeMethodName(comp.name, node.id)}(ps_${s}, ${boundArg})`);
1758
1351
  lines.push(`\t\t\t}()`);
1759
1352
  lines.push(`\t\t}`);
1760
1353
  }
1761
1354
  lines.push(`\t\twg.Wait()`);
1762
- // 3) COMMIT (ascending index): interpret + materialize deterministically — lowest-index failure wins.
1355
+ // 3) COMMIT (ascending index): interpret + INLINE de-box deterministically — lowest-index failure wins.
1356
+ // Uniform seam: every member's slot holds a single result WIRE (WireValue); the inline de-box
1357
+ // (renderResultDeBox) classifies it against the STATICALLY declared result type and produces the
1358
+ // structured Error Value on a mismatch (byte-equal codes to run_behavior's outType check, so ≡ holds).
1763
1359
  for (const i of refMembers) {
1764
1360
  const node = comp.body[i];
1765
1361
  const meta = metas[i];
1766
1362
  const s = sanitize(node.id);
1767
1363
  const ref = typedNodes.get(node.id);
1768
- const oc = `row_${s}`;
1769
- const top = recordTop(ref);
1770
- const namedTop = top !== null && top.kind === "named";
1771
- const deBox = top !== null;
1772
- // a NAMED top decodes in place (decodeWire_<Name> → oc → field copy); an arr/opt/map top assembles
1773
- // via decodeWireResult_* (the same decode recursion, one per record) into the typed local directly.
1774
1364
  lines.push(`\t\tif run_${s} {`);
1775
1365
  if (meta.policy === "continue") {
1776
- lines.push(`\t\t\tif ${oc}Err == nil {`);
1777
- if (namedTop) {
1778
- lines.push(`\t\t\t\tif ${oc}, ${oc}DErr := ${goDecodeNamedName(top.innerName)}(wire_${s}); ${oc}DErr == nil {`);
1779
- lines.push(emitRowCopy(typedLocal(node.id), oc, ref, plan, 5));
1780
- lines.push(`\t\t\t\t\tproduced_${s} = true`);
1781
- lines.push(`\t\t\t\t}`);
1782
- }
1783
- else if (deBox) {
1784
- lines.push(`\t\t\t\tif res_${s}, res_${s}DErr := ${goDecodeResultName(comp.name, node.id)}(wire_${s}); res_${s}DErr == nil {`);
1785
- lines.push(`\t\t\t\t\t${typedLocal(node.id)} = res_${s}`);
1786
- lines.push(`\t\t\t\t\tproduced_${s} = true`);
1787
- lines.push(`\t\t\t\t}`);
1788
- }
1789
- else {
1790
- lines.push(emitRowCopy(typedLocal(node.id), oc, ref, plan, 4));
1791
- lines.push(`\t\t\t\tproduced_${s} = true`);
1792
- }
1366
+ // continue: a failed member (leaf failure OR de-box mismatch) commits no Port (defensive — covered
1367
+ // componentRef members are always 'fail' policy today). A local skip, NOT a runner-wide propagate.
1368
+ const nodeGo = renderTypeRef(ref);
1369
+ const nodeZeroFail = (e) => `return ${goZero(ref)}, ${e}`;
1370
+ lines.push(`\t\t\tif row_${s}Err == nil {`);
1371
+ lines.push(`\t\t\t\tdec_${s}, dec_${s}DErr := func() (${nodeGo}, error) {`);
1372
+ lines.push(`\t\t\t\t\tvar out ${nodeGo}`);
1373
+ lines.push(renderResultDeBox(ref, "out", `wire_${s}`, node.id, plan, "\t\t\t\t\t", nodeZeroFail));
1374
+ lines.push(`\t\t\t\t\treturn out, nil`);
1375
+ lines.push(`\t\t\t\t}()`);
1376
+ lines.push(`\t\t\t\tif dec_${s}DErr == nil {`);
1377
+ lines.push(`\t\t\t\t\t${typedLocal(node.id)} = dec_${s}`);
1378
+ lines.push(`\t\t\t\t\tproduced_${s} = true`);
1379
+ lines.push(`\t\t\t\t}`);
1793
1380
  lines.push(`\t\t\t}`);
1794
1381
  }
1795
1382
  else {
1796
- lines.push(`\t\t\tif ${oc}Err != nil {`);
1797
- lines.push(`\t\t\t\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${JSON.stringify(meta.policy === "retry" ? "retry" : "fail")}, ${oc}Err)`);
1383
+ lines.push(`\t\t\tif row_${s}Err != nil {`);
1384
+ lines.push(`\t\t\t\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${JSON.stringify(meta.policy === "retry" ? "retry" : "fail")}, row_${s}Err)`);
1798
1385
  lines.push(`\t\t\t}`);
1799
- if (namedTop) {
1800
- lines.push(`\t\t\t${oc}, ${oc}DErr := ${goDecodeNamedName(top.innerName)}(wire_${s})`);
1801
- lines.push(`\t\t\tif ${oc}DErr != nil {`);
1802
- lines.push(`\t\t\t\treturn ${zeroOut}, ${oc}DErr`);
1803
- lines.push(`\t\t\t}`);
1804
- lines.push(emitRowCopy(typedLocal(node.id), oc, ref, plan, 3));
1805
- }
1806
- else if (deBox) {
1807
- lines.push(`\t\t\tres_${s}, res_${s}DErr := ${goDecodeResultName(comp.name, node.id)}(wire_${s})`);
1808
- lines.push(`\t\t\tif res_${s}DErr != nil {`);
1809
- lines.push(`\t\t\t\treturn ${zeroOut}, res_${s}DErr`);
1810
- lines.push(`\t\t\t}`);
1811
- lines.push(`\t\t\t${typedLocal(node.id)} = res_${s}`);
1812
- }
1813
- else {
1814
- lines.push(emitRowCopy(typedLocal(node.id), oc, ref, plan, 3));
1815
- }
1386
+ lines.push(renderResultDeBox(ref, typedLocal(node.id), `wire_${s}`, node.id, plan, "\t\t\t", returnZeroFail(zeroOut)));
1816
1387
  lines.push(`\t\t\tproduced_${s} = true`);
1817
1388
  }
1818
1389
  lines.push(`\t\t}`);
@@ -1833,7 +1404,7 @@ function emitParallelStageArm(comp, stage, atPos, concurrency, metas, typedNodes
1833
1404
  * consumer (graphddb) drives it and keeps the struct native. A Value observation is produced ONLY
1834
1405
  * by the separate serialize wrapper (run_native_raw_<comp>, below), the single outer Value boundary.
1835
1406
  */
1836
- function emitNativeRawRunner(comp, plan, flags) {
1407
+ function emitNativeRawRunner(comp, plan, flags, wire) {
1837
1408
  const ep = execPlan(comp);
1838
1409
  const order = ep.order;
1839
1410
  const cplan = buildComponentPlan(comp, goStraightlineInternals.dialect, "scope");
@@ -1854,6 +1425,9 @@ function emitNativeRawRunner(comp, plan, flags) {
1854
1425
  const outRef = comp.outputType !== undefined ? deriveTypeRef(comp.outputType, plan) : undefined;
1855
1426
  const outStructType = outRef ? renderTypeRef(outRef) : `${PKG}.Value`;
1856
1427
  const zeroOut = outRef ? goZero(outRef) : "nil";
1428
+ // ONE de-box temp counter across all at-fn-scope sequential nodes so sibling reads never collide on a
1429
+ // temp name (a gated / loop-scoped arm has its own Go scope, so it may keep a fresh counter).
1430
+ const seqCtr = { n: 0 };
1857
1431
  const lines = [];
1858
1432
  lines.push(`// ${runnerName(comp.name)} — the STRUCT-RETURNING combined read (bc#77/#87): the fully`);
1859
1433
  lines.push(`// de-plumbed path. Ports are a native struct (direct field assignment); the handler`);
@@ -1867,11 +1441,12 @@ function emitNativeRawRunner(comp, plan, flags) {
1867
1441
  lines.push(`// index order so the observed value / op multiset / failure precedence byte-match run_behavior`);
1868
1442
  lines.push(`// (the goroutine spawn is the ONLY runtime element — the WHAT is baked). The output is a typed`);
1869
1443
  lines.push(`// struct/value assembled by struct literal + field access — the consumer keeps it native.`);
1870
- // FULLY CONCRETE: GENERIC over the per-component CONCRETE handler interface ${handlerIfaceName(comp.name)},
1871
- // whose Node_* methods return the concrete per-node row struct (typed fields = the node's outType).
1872
- // The covered result plane carries no boxed ports / boxed value / dynamic accessor / semantic type-
1873
- // assert on a row value — the runner reads row.<Field> directly and copies each into the outType local.
1874
- lines.push(`func ${runnerName(comp.name)}[H ${handlerIfaceName(comp.name)}](handlers H, in ${inStructName(comp.name)}) (${outStructType}, error) {`);
1444
+ // FULLY CONCRETE + NON-GENERIC: the runner takes the consumer's CONCRETE ${handlerTypeName(comp.name)}
1445
+ // handler by value and calls h.Node_*(...) DIRECTLY (a Go generic method call goes through a dictionary,
1446
+ // a Go interface through a vtable BOTH are dynamic dispatch, so the covered plane uses neither). Each
1447
+ // Node_* returns the node's result WIRE (a single ${wire.value}); the runner de-boxes it INLINE
1448
+ // (fully-unrolled probe/match no decode helper, no output recursion) into the node's outType struct.
1449
+ lines.push(`func ${runnerName(comp.name)}(handlers ${handlerTypeName(comp.name)}, in ${inStructName(comp.name)}) (${outStructType}, error) {`);
1875
1450
  lines.push(`\t_ = in`);
1876
1451
  for (const k of order.keys()) {
1877
1452
  const node = comp.body[order[k]];
@@ -1895,7 +1470,7 @@ function emitNativeRawRunner(comp, plan, flags) {
1895
1470
  // ascending-sorted stages), so we emit the block at the first member and skip the rest.
1896
1471
  const stage = ep.parallelStageOf.get(i);
1897
1472
  if (stage !== undefined && stage[0] === i) {
1898
- lines.push(emitParallelStageArm(comp, stage, k, ep.concurrency, metas, typedNodes, plan, priorNodeAt, zeroOut, flags));
1473
+ lines.push(emitParallelStageArm(comp, stage, k, ep.concurrency, metas, typedNodes, plan, priorNodeAt, zeroOut, flags, wire));
1899
1474
  k += stage.length - 1;
1900
1475
  continue;
1901
1476
  }
@@ -1971,76 +1546,36 @@ function emitNativeRawRunner(comp, plan, flags) {
1971
1546
  inits.push(emitPortInit(pn, node.ports[pn], comp, plan, typedNodes, (h) => priorNodeAt(h, k)));
1972
1547
  }
1973
1548
  lines.push(`${indent}ports_${s} := ${structName}{${inits.join(", ")}}`);
1974
- const oc = `row_${s}`;
1975
- const copy = (ind) => emitRowCopy(typedLocal(node.id), oc, ref, plan, ind.length);
1976
- // a NAMED top returns a WireRow, decoded in place (decodeWire_<Name> oc field copy). An arr/opt/map
1977
- // top returns []WireRow / nilable WireRow / map[string]WireRow, assembled via decodeWireResult_* (the same
1978
- // decode recursion, one per record). Either way a de-box mismatch fails closed with the structured Error
1979
- // Value (byte-equal codes to run_behavior's outType check, so ≡ holds). A non-de-box node keeps its
1980
- // direct concrete-row return + field copy.
1981
- const top = recordTop(ref);
1982
- const namedTop = top !== null && top.kind === "named";
1983
- const deBox = top !== null;
1549
+ // uniform seam: the handler returns a single result WIRE (${wire.value}); the inline de-box
1550
+ // (renderResultDeBox) classifies it against the STATICALLY declared result type and produces the
1551
+ // structured Error Value on a mismatch (byte-equal codes to run_behavior's outType check, so holds).
1984
1552
  if (meta.policy === "continue") {
1985
- // continue: a failed node (leaf failure OR de-box mismatch) produces no Port — the downstream
1986
- // Skip propagation is what `continue` means. Only a clean decode commits the result.
1987
- if (namedTop) {
1988
- lines.push(`${indent}if wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg}); wire_${s}Err == nil {`);
1989
- lines.push(`${indent}\tif ${oc}, ${oc}DErr := ${goDecodeNamedName(top.innerName)}(wire_${s}); ${oc}DErr == nil {`);
1990
- lines.push(copy(indent + "\t\t"));
1991
- lines.push(`${indent}\t\tproduced_${s} = true`);
1992
- lines.push(`${indent}\t}`);
1993
- lines.push(`${indent}}`);
1994
- }
1995
- else if (deBox) {
1996
- lines.push(`${indent}if wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg}); wire_${s}Err == nil {`);
1997
- lines.push(`${indent}\tif res_${s}, res_${s}DErr := ${goDecodeResultName(comp.name, node.id)}(wire_${s}); res_${s}DErr == nil {`);
1998
- lines.push(`${indent}\t\t${typedLocal(node.id)} = res_${s}`);
1999
- lines.push(`${indent}\t\tproduced_${s} = true`);
2000
- lines.push(`${indent}\t}`);
2001
- lines.push(`${indent}}`);
2002
- }
2003
- else {
2004
- lines.push(`${indent}if ${oc}, ${oc}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg}); ${oc}Err == nil {`);
2005
- lines.push(copy(indent + "\t"));
2006
- lines.push(`${indent}\tproduced_${s} = true`);
2007
- lines.push(`${indent}}`);
2008
- }
1553
+ // continue: a failed node (leaf failure OR de-box mismatch) produces no Port — the downstream Skip
1554
+ // propagation is what `continue` means. The inline de-box runs in a local closure so a mismatch is a
1555
+ // LOCAL skip (not a runner-wide propagate); only a clean decode commits. (Covered componentRef nodes
1556
+ // are always 'fail' policy today this arm is defensive.)
1557
+ const nodeGo = renderTypeRef(ref);
1558
+ const nodeZeroFail = (e) => `return ${goZero(ref)}, ${e}`;
1559
+ lines.push(`${indent}if wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg}); wire_${s}Err == nil {`);
1560
+ lines.push(`${indent}\tdec_${s}, dec_${s}DErr := func() (${nodeGo}, error) {`);
1561
+ lines.push(`${indent}\t\tvar out ${nodeGo}`);
1562
+ lines.push(renderResultDeBox(ref, "out", `wire_${s}`, node.id, plan, `${indent}\t\t`, nodeZeroFail, seqCtr));
1563
+ lines.push(`${indent}\t\treturn out, nil`);
1564
+ lines.push(`${indent}\t}()`);
1565
+ lines.push(`${indent}\tif dec_${s}DErr == nil {`);
1566
+ lines.push(`${indent}\t\t${typedLocal(node.id)} = dec_${s}`);
1567
+ lines.push(`${indent}\t\tproduced_${s} = true`);
1568
+ lines.push(`${indent}\t}`);
1569
+ lines.push(`${indent}}`);
2009
1570
  }
2010
1571
  else {
2011
1572
  const policyLit = JSON.stringify(meta.policy === "retry" ? "retry" : "fail");
2012
- if (namedTop) {
2013
- lines.push(`${indent}wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg})`);
2014
- lines.push(`${indent}if wire_${s}Err != nil {`);
2015
- lines.push(`${indent}\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${policyLit}, wire_${s}Err)`);
2016
- lines.push(`${indent}}`);
2017
- lines.push(`${indent}${oc}, ${oc}DErr := ${goDecodeNamedName(top.innerName)}(wire_${s})`);
2018
- lines.push(`${indent}if ${oc}DErr != nil {`);
2019
- lines.push(`${indent}\treturn ${zeroOut}, ${oc}DErr`);
2020
- lines.push(`${indent}}`);
2021
- lines.push(copy(indent));
2022
- lines.push(`${indent}produced_${s} = true`);
2023
- }
2024
- else if (deBox) {
2025
- lines.push(`${indent}wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg})`);
2026
- lines.push(`${indent}if wire_${s}Err != nil {`);
2027
- lines.push(`${indent}\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${policyLit}, wire_${s}Err)`);
2028
- lines.push(`${indent}}`);
2029
- lines.push(`${indent}res_${s}, res_${s}DErr := ${goDecodeResultName(comp.name, node.id)}(wire_${s})`);
2030
- lines.push(`${indent}if res_${s}DErr != nil {`);
2031
- lines.push(`${indent}\treturn ${zeroOut}, res_${s}DErr`);
2032
- lines.push(`${indent}}`);
2033
- lines.push(`${indent}${typedLocal(node.id)} = res_${s}`);
2034
- lines.push(`${indent}produced_${s} = true`);
2035
- }
2036
- else {
2037
- lines.push(`${indent}${oc}, ${oc}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg})`);
2038
- lines.push(`${indent}if ${oc}Err != nil {`);
2039
- lines.push(`${indent}\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${policyLit}, ${oc}Err)`);
2040
- lines.push(`${indent}}`);
2041
- lines.push(copy(indent));
2042
- lines.push(`${indent}produced_${s} = true`);
2043
- }
1573
+ lines.push(`${indent}wire_${s}, wire_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(ports_${s}, ${boundArg})`);
1574
+ lines.push(`${indent}if wire_${s}Err != nil {`);
1575
+ lines.push(`${indent}\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, ${policyLit}, wire_${s}Err)`);
1576
+ lines.push(`${indent}}`);
1577
+ lines.push(renderResultDeBox(ref, typedLocal(node.id), `wire_${s}`, node.id, plan, indent, returnZeroFail(zeroOut), seqCtr));
1578
+ lines.push(`${indent}produced_${s} = true`);
2044
1579
  }
2045
1580
  for (const c of closers)
2046
1581
  lines.push(c);
@@ -2138,13 +1673,13 @@ function emitMapArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut, f
2138
1673
  // over collection (typed field access to the parent node's arr — no serialize).
2139
1674
  lines.push(`${indent}over_${s} := ${overExpr}`);
2140
1675
  lines.push(`${indent}${typedLocal(node.id)} = make(${elemGo}, 0, len(over_${s}))`);
1676
+ // each element is de-boxed strictly INLINE: the handler returns the per-element WIRE and the arm decodes
1677
+ // it against the element ref (the `into` field's type for map...into, else the element type). A de-box
1678
+ // mismatch fails closed regardless of elementPolicy (matching the interpreter's whole-node outType
1679
+ // throw); elementPolicy still governs the handler's own leaf failures only.
2141
1680
  const elemRowRef = mapElemRowRef(node, arrRef, plan);
2142
- // a record element is de-boxed strictly: the handler returns the element WIRE and the arm decodes it via
2143
- // decodeWireElem_* (closing the scan-row silent-default hole). A de-box mismatch fails closed regardless
2144
- // of elementPolicy (matching the interpreter's whole-node outType throw); elementPolicy still governs the
2145
- // handler's own leaf failures only.
2146
- const elemDeBox = elemRowRef.kind === "named";
2147
- const decElemFn = elemDeBox ? goDecodeElemName(comp.name, node.id) : "";
1681
+ const elemRowGo = renderTypeRef(elemRowRef);
1682
+ const renderElemDeBox = (target, src, il) => renderResultDeBox(elemRowRef, target, src, node.id, plan, il, returnZeroFail(zeroOut));
2148
1683
  // emit the per-element guard keep-gate (#108). `il` = indent, `elemVar` = the over element loop var.
2149
1684
  // On skip: batched → `continue` (element excluded from items + keptOver); non-batched → `continue`.
2150
1685
  const emitGuard = (il, elemVar) => {
@@ -2161,9 +1696,9 @@ function emitMapArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut, f
2161
1696
  };
2162
1697
  if (batched) {
2163
1698
  // BATCHED (#86 pt2 into / #93 shape 3 no-into / #108 guarded no-into): build kept-element ports,
2164
- // dispatch ONCE. The concrete Node_* returns RawRow{Rows []RawElem} aligned to items (or an error).
1699
+ // dispatch ONCE. The concrete Node_* returns the aligned per-element WIRES ([]WireValue) or an error.
2165
1700
  // With a guard, `items` (and, for into, `keptOver`) hold only kept elements — matching run_behavior's
2166
- // keptIdx-aligned batch. `into` is never combined with a guard (rejected). no-into collects each row.
1701
+ // keptIdx-aligned batch. `into` is never combined with a guard (rejected). Each wire is de-boxed inline.
2167
1702
  lines.push(`${indent}items_${s} := make([]${structName}, 0, len(over_${s}))`);
2168
1703
  if (hasInto)
2169
1704
  lines.push(`${indent}keptOver_${s} := make([]${overElemGo}, 0, len(over_${s}))`);
@@ -2181,37 +1716,22 @@ function emitMapArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut, f
2181
1716
  lines.push(`${indent}\tbp_${s} := ${batchStruct}{Items: items_${s}}`);
2182
1717
  lines.push(`${indent}\tmo_${s}, mo_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(bp_${s}, nil)`);
2183
1718
  lines.push(`${indent}\tif mo_${s}Err != nil {`, `${indent}\t\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, "fail", mo_${s}Err)`, `${indent}\t}`);
2184
- // the batch length aligns to items (the handler returns the element WIRES aligned; a record element
2185
- // is de-boxed below, a non-record element is the concrete batch row).
2186
- const batchLen = elemDeBox ? `len(mo_${s})` : `len(mo_${s}.Rows)`;
2187
- const batchAt = (mk) => (elemDeBox ? `mo_${s}[${mk}]` : `mo_${s}.Rows[${mk}]`);
2188
- lines.push(`${indent}\tif ${batchLen} != len(items_${s}) {`, `${indent}\t\treturn ${zeroOut}, ${goErr("MAP_BATCH_RESULT_MISMATCH", `fmt.Sprintf("map '${node.id}': batched handler must return a list aligned to items (want %d)", len(items_${s}))`)}`, `${indent}\t}`);
1719
+ lines.push(`${indent}\tif len(mo_${s}) != len(items_${s}) {`, `${indent}\t\treturn ${zeroOut}, ${goErr("MAP_BATCH_RESULT_MISMATCH", `fmt.Sprintf("map '${node.id}': batched handler must return a list aligned to items (want %d)", len(items_${s}))`)}`, `${indent}\t}`);
2189
1720
  if (hasInto) {
2190
- // #86 pt2: zip-attach the into field onto each kept over element (augmented element copier).
1721
+ // #86 pt2: de-box each aligned element wire (into the `into` field's type), then zip-attach onto the
1722
+ // kept over element (augmented element copier).
2191
1723
  lines.push(`${indent}\tfor mk_${s} := range keptOver_${s} {`);
2192
- if (elemDeBox) {
2193
- lines.push(`${indent}\t\telm_${s}, elm_${s}Err := ${decElemFn}(${batchAt(`mk_${s}`)})`);
2194
- lines.push(`${indent}\t\tif elm_${s}Err != nil {`, `${indent}\t\t\treturn ${zeroOut}, elm_${s}Err`, `${indent}\t\t}`);
2195
- lines.push(`${indent}\t\tel_${s} := ${elemMat}(keptOver_${s}[mk_${s}], elm_${s})`);
2196
- }
2197
- else {
2198
- lines.push(`${indent}\t\tel_${s} := ${elemMat}(keptOver_${s}[mk_${s}], ${batchAt(`mk_${s}`)})`);
2199
- }
1724
+ lines.push(`${indent}\t\tvar dec_${s} ${elemRowGo}`);
1725
+ lines.push(renderElemDeBox(`dec_${s}`, `mo_${s}[mk_${s}]`, `${indent}\t\t`));
1726
+ lines.push(`${indent}\t\tel_${s} := ${elemMat}(keptOver_${s}[mk_${s}], dec_${s})`);
2200
1727
  lines.push(`${indent}\t\t${typedLocal(node.id)} = append(${typedLocal(node.id)}, el_${s})`);
2201
1728
  lines.push(`${indent}\t}`);
2202
1729
  }
2203
1730
  else {
2204
- // #93 shape 3 / #108: collect each element DIRECTLY from the aligned per-element row (field copy).
2205
- lines.push(`${indent}\tfor mk_${s} := 0; mk_${s} < ${batchLen}; mk_${s}++ {`);
1731
+ // #93 shape 3 / #108: de-box each aligned per-element wire DIRECTLY into the element (result = kept).
1732
+ lines.push(`${indent}\tfor mk_${s} := 0; mk_${s} < len(mo_${s}); mk_${s}++ {`);
2206
1733
  lines.push(`${indent}\t\tvar el_${s} ${renderTypeRef(arrRef.elem)}`);
2207
- if (elemDeBox) {
2208
- lines.push(`${indent}\t\telm_${s}, elm_${s}Err := ${decElemFn}(${batchAt(`mk_${s}`)})`);
2209
- lines.push(`${indent}\t\tif elm_${s}Err != nil {`, `${indent}\t\t\treturn ${zeroOut}, elm_${s}Err`, `${indent}\t\t}`);
2210
- lines.push(emitRowCopy(`el_${s}`, `elm_${s}`, elemRowRef, plan, indent.length + 2));
2211
- }
2212
- else {
2213
- lines.push(emitRowCopy(`el_${s}`, batchAt(`mk_${s}`), elemRowRef, plan, indent.length + 2));
2214
- }
1734
+ lines.push(renderElemDeBox(`el_${s}`, `mo_${s}[mk_${s}]`, `${indent}\t\t`));
2215
1735
  lines.push(`${indent}\t\t${typedLocal(node.id)} = append(${typedLocal(node.id)}, el_${s})`);
2216
1736
  lines.push(`${indent}\t}`);
2217
1737
  }
@@ -2220,7 +1740,7 @@ function emitMapArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut, f
2220
1740
  else {
2221
1741
  // #93 shape 2 / #108: NON-batched map — dispatch the child handler ONCE PER KEPT ELEMENT (N physical
2222
1742
  // requests, matching run_behavior's per-element loop). A guarded element that fails `when` is skipped
2223
- // (no dispatch, excluded from the result). The concrete Node_* returns ONE RawElem_.
1743
+ // (no dispatch, excluded from the result). The concrete Node_* returns ONE element WIRE (WireValue).
2224
1744
  lines.push(`${indent}for mk_${s} := range over_${s} {`);
2225
1745
  lines.push(`${indent}\t${elemLocal(s)} := over_${s}[mk_${s}]`);
2226
1746
  for (const l of emitGuard(indent + "\t", elemLocal(s)))
@@ -2240,20 +1760,17 @@ function emitMapArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut, f
2240
1760
  else {
2241
1761
  lines.push(`${indent}\tif mo_${s}Err != nil {`, `${indent}\t\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, "fail", mo_${s}Err)`, `${indent}\t}`);
2242
1762
  }
2243
- // a record element's wire is de-boxed strictly. A de-box mismatch fails closed regardless of
1763
+ // the element's wire is de-boxed strictly INLINE. A de-box mismatch fails closed regardless of
2244
1764
  // elementPolicy (≡ the interpreter's whole-node outType throw); elementPolicy governs the handler's
2245
1765
  // own leaf failures only (above).
2246
- const elemVar = elemDeBox ? `elm_${s}` : `mo_${s}`;
2247
- if (elemDeBox) {
2248
- lines.push(`${indent}\telm_${s}, elm_${s}Err := ${decElemFn}(mo_${s})`);
2249
- lines.push(`${indent}\tif elm_${s}Err != nil {`, `${indent}\t\treturn ${zeroOut}, elm_${s}Err`, `${indent}\t}`);
2250
- }
2251
1766
  if (hasInto) {
2252
- lines.push(`${indent}\tel_${s} := ${elemMat}(${elemLocal(s)}, ${elemVar})`);
1767
+ lines.push(`${indent}\tvar dec_${s} ${elemRowGo}`);
1768
+ lines.push(renderElemDeBox(`dec_${s}`, `mo_${s}`, `${indent}\t`));
1769
+ lines.push(`${indent}\tel_${s} := ${elemMat}(${elemLocal(s)}, dec_${s})`);
2253
1770
  }
2254
1771
  else {
2255
1772
  lines.push(`${indent}\tvar el_${s} ${renderTypeRef(arrRef.elem)}`);
2256
- lines.push(emitRowCopy(`el_${s}`, elemVar, elemRowRef, plan, indent.length + 1));
1773
+ lines.push(renderElemDeBox(`el_${s}`, `mo_${s}`, `${indent}\t`));
2257
1774
  }
2258
1775
  lines.push(`${indent}\t${typedLocal(node.id)} = append(${typedLocal(node.id)}, el_${s})`);
2259
1776
  lines.push(`${indent}}`);
@@ -2324,10 +1841,9 @@ function emitFanoutArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut
2324
1841
  // empty id-list => empty connection (handler not called), matching run_behavior.
2325
1842
  lines.push(`${indent}if len(pi_${s}) > 0 {`);
2326
1843
  lines.push(`${indent}\tbp_${s} := ${batchStruct}{Items: pi_${s}}`);
2327
- // the fanout element row is a named record → the handler returns the aligned element WIRES ([]WireRow),
2328
- // and each is de-boxed strictly via decodeWireElem_* (a de-box mismatch fails closed). A DANGLING id is
2329
- // a nil wire → the zero element (empty dedupeKey), which the dangling drop below excludes.
2330
- const decElemFn = goDecodeElemName(comp.name, node.id);
1844
+ // the handler returns the aligned per-id element WIRES (one nilable WireValue per id); each present
1845
+ // body is de-boxed strictly INLINE (a de-box mismatch fails closed). A DANGLING id is a nil wire → the
1846
+ // zero element (empty dedupeKey), which the dangling drop below excludes.
2331
1847
  lines.push(`${indent}\tfo_${s}, fo_${s}Err := handlers.${nodeMethodName(comp.name, node.id)}(bp_${s}, nil)`);
2332
1848
  lines.push(`${indent}\tif fo_${s}Err != nil {`, `${indent}\t\treturn ${zeroOut}, opFailed(${JSON.stringify(node.id)}, "fail", fo_${s}Err)`, `${indent}\t}`);
2333
1849
  lines.push(`${indent}\tif len(fo_${s}) != len(pi_${s}) {`, `${indent}\t\treturn ${zeroOut}, ${goErr("FANOUT_BATCH_RESULT_MISMATCH", `fmt.Sprintf("fanout '${node.id}': batched handler must return a list aligned to the deduped id list (want %d)", len(pi_${s}))`)}`, `${indent}\t}`);
@@ -2339,9 +1855,7 @@ function emitFanoutArm(comp, node, atPos, typedNodes, plan, priorNodeAt, zeroOut
2339
1855
  lines.push(`${indent}\tfor fi_${s} := range fo_${s} {`);
2340
1856
  lines.push(`${indent}\t\tvar el_${s} ${elemGo}`);
2341
1857
  lines.push(`${indent}\t\tif fo_${s}[fi_${s}] != nil {`);
2342
- lines.push(`${indent}\t\t\telm_${s}, elm_${s}Err := ${decElemFn}(fo_${s}[fi_${s}])`);
2343
- lines.push(`${indent}\t\t\tif elm_${s}Err != nil {`, `${indent}\t\t\t\treturn ${zeroOut}, elm_${s}Err`, `${indent}\t\t\t}`);
2344
- lines.push(emitRowCopy(`el_${s}`, `elm_${s}`, elemRef, plan, indent.length + 3));
1858
+ lines.push(renderResultDeBox(elemRef, `el_${s}`, `(*fo_${s}[fi_${s}])`, node.id, plan, `${indent}\t\t\t`, returnZeroFail(zeroOut)));
2345
1859
  lines.push(`${indent}\t\t}`);
2346
1860
  lines.push(`${indent}\t\tkey_${s} := el_${s}.${dkGo}`);
2347
1861
  if (f.drop === "dangling") {
@@ -2787,7 +2301,7 @@ var ComponentNamesNativeRaw = []string{${native.map((c) => JSON.stringify(c.name
2787
2301
  * mismatch Sprintf, `strings` for a concat builder, `sync` for a parallel stage). ExpectedSpecVersions
2788
2302
  * stays as a local `var` for provenance, but the old `dslcontracts.SpecVersions` skew `init()` is GONE
2789
2303
  * (change #5 — there is no runtime to skew against once the module is runtime-free). */
2790
- function emitMinimalHeader(ctx, needStrings, needSync, needFmt, needMath, needStrconv = false) {
2304
+ function emitMinimalHeader(ctx, needStrings, needSync, needFmt, needMath, needStrconv = false, wireImport) {
2791
2305
  const sv = ctx.specVersions;
2792
2306
  const imports = [];
2793
2307
  if (needFmt)
@@ -2800,6 +2314,10 @@ function emitMinimalHeader(ctx, needStrings, needSync, needFmt, needMath, needSt
2800
2314
  imports.push(`\t"strings"`);
2801
2315
  if (needSync)
2802
2316
  imports.push(`\t"sync"`);
2317
+ // a configured consumer wire package (goWire.import) — the covered module references its CONCRETE
2318
+ // WireValue/WireRow/WireList types (default: in-package, no import).
2319
+ if (wireImport !== undefined)
2320
+ imports.push(`\t${JSON.stringify(wireImport)}`);
2803
2321
  const importBlock = imports.length > 0 ? `\nimport (\n${imports.join("\n")}\n)\n` : "";
2804
2322
  return `// GENERATED by behavior-contracts (bc#90, go-typed-native — the RUNTIME-FREE covered read de-box) — DO NOT EDIT.
2805
2323
  // Input: portable component-graph IR only. Every component here is a COVERED READ (sequential typed
@@ -2825,17 +2343,16 @@ function emit(ctx) {
2825
2343
  // #108: reset the native-expr helper-usage accumulator (set by the cond/guard compiler when it emits
2826
2344
  // a fallible checked-arith helper call — determines whether the helper library + `math` import ship).
2827
2345
  goExprUsed.helpers = false;
2346
+ const wire = resolveGoWire(ctx);
2828
2347
  // Emit the runners first so the nv* helper usage flags are known.
2829
2348
  const flags = { bind: false, field: false, cat: false, arr: false };
2830
2349
  const structs = [];
2831
2350
  const inStructs = [];
2832
- const rowStructs = [];
2833
- const handlerIfaces = [];
2834
2351
  const elemCopiers = [];
2835
2352
  const runnerCodes = [];
2836
- // the generated strict de-box functions (deduped by named type across all covered components).
2837
- const decodeFns = [];
2838
- const decodeEmitted = new Set();
2353
+ // every covered node returns a WireValue the inline de-box classifies the wire seam (probe kind
2354
+ // consts + probe RESULT structs) is emitted once whenever any handler node exists.
2355
+ const anyWire = native.some((c) => c.body.some((n) => !("cond" in n)));
2839
2356
  for (const c of native) {
2840
2357
  inStructs.push(emitInStruct(c, plan));
2841
2358
  const typedNodes = new Map();
@@ -2861,18 +2378,11 @@ function emit(ctx) {
2861
2378
  structs.push(emitPortsStruct(c, n, undefined, plan, typedNodes));
2862
2379
  }
2863
2380
  }
2864
- // fail closed for a record inside a non-named top (never a silent trust) — before emitting anything.
2865
- assertDeBoxableResults(c, typedNodes, plan);
2866
- // CONCRETE per-node row structs + the per-component handler interface (the fully-concrete seam).
2867
- rowStructs.push(emitRawRowStructs(c, typedNodes, plan));
2868
- handlerIfaces.push(emitHandlerInterface(c, typedNodes, plan));
2869
- // the strict de-box functions for this component's de-box-eligible (named-record) reads.
2870
- emitNodeDecodeFns(c, typedNodes, plan, decodeEmitted, decodeFns);
2871
- // augmented-element copiers for covered map...into nodes (over fields + concrete into row).
2381
+ // augmented-element copiers for covered map...into nodes (over fields + the de-boxed into value).
2872
2382
  const mm = emitMapElemMaterializers(c, typedNodes, plan);
2873
2383
  if (mm)
2874
2384
  elemCopiers.push(mm);
2875
- const r = emitNativeRawRunner(c, plan, flags);
2385
+ const r = emitNativeRawRunner(c, plan, flags, wire);
2876
2386
  runnerCodes.push(r.code);
2877
2387
  }
2878
2388
  const structSurface = emitStructSurface(native);
@@ -2901,37 +2411,31 @@ function emit(ctx) {
2901
2411
  // #108: `math` is imported iff the native-expr compiler emitted a fallible helper (bcExpr_modF uses
2902
2412
  // math.Mod). The helper library itself is baked into the module only when used (goExprUsed.helpers).
2903
2413
  const needMath = goExprUsed.helpers;
2904
- // `strconv` is imported iff a generated de-box parses a numeric field (int/float range check).
2905
- const needStrconv = decodeFns.some((f) => f.includes("strconv."));
2906
- const header = emitMinimalHeader(ctx, false, needSync, needFmt, needMath, needStrconv);
2414
+ // `strconv` is imported iff a generated inline de-box parses a numeric field (int/float range check).
2415
+ const needStrconv = runnerCodes.some((c) => c.includes("strconv."));
2416
+ const header = emitMinimalHeader(ctx, false, needSync, needFmt, needMath, needStrconv, wire.import);
2907
2417
  const banner = `// COMBINED READ layer (bc#90 — the RUNTIME-FREE read de-box; STRUCT-ONLY, FULLY-NATIVE surface). A
2908
2418
  // covered read is a strictly-sequential typed componentRef chain (point reads + relationKind:single
2909
2419
  // children), emitted ONLY here: each node builds a native ports struct by direct field assignment (every
2910
2420
  // port is a CONCRETE Go value — string / bool / []string projection / int64 limit — NO boxed Value, NO
2911
- // PortReader accessor); the CONCRETE per-component handler interface (Handler_<comp>) takes a typed
2912
- // produced-aware 'bound' pointer and returns a CONCRETE per-node row struct (Row_<comp>_<node>, typed
2913
- // fields = the node's outType) whose fields the runner reads DIRECTLY and copies into the node's outType
2914
- // struct. The covered plane carries NO bc-runtime reference at all failures use the LOCAL
2915
- // *BehaviorError (same codes, byte-equal to run_behavior). Exec is INLINE sequential (no plan driver) so
2916
- // a relation child reads the parent's REAL struct result via direct field access and the child-present
2421
+ // PortReader accessor); the runner takes the consumer's CONCRETE Handler_<comp> handler by
2422
+ // value and calls h.Node_*(...) DIRECTLY (no interface, no generics zero dynamic dispatch). Each Node_*
2423
+ // takes a typed produced-aware 'bound' pointer and returns the node's result WIRE (a single ${wire.value});
2424
+ // the runner de-boxes it INLINE (fully-unrolled probe/match no decode helper, no output recursion) into
2425
+ // the node's outType struct. The covered plane carries NO bc-runtime reference at all — failures use the
2426
+ // LOCAL *BehaviorError (same codes, byte-equal to run_behavior). Exec is INLINE sequential (no plan driver)
2427
+ // so a relation child reads the parent's REAL struct result via direct field access and the child-present
2917
2428
  // decision is made from the real parent value — relationSingle / connection converge with run_behavior
2918
- // (fixes #323/#74). The exposed API is the STRUCT-returning RunNativeRawStruct_<comp> (the consumer
2919
- // keeps the model native — no serialization on the read hot path). This module is FULLY NATIVE: a naive
2920
- // grep for boxing primitives OR for the bc-runtime package finds nothing, by design (bc#90/runtime-free).`;
2429
+ // (fixes #323/#74). The exposed API is the STRUCT-returning RunNativeRawStruct_<comp> (the consumer keeps
2430
+ // the model native — no serialization on the read hot path). This module is FULLY NATIVE: a naive grep for
2431
+ // boxing primitives OR for the bc-runtime package finds nothing, by design (bc#90/runtime-free).`;
2921
2432
  const sections = [
2922
2433
  banner,
2923
2434
  `// Local concrete failure type (runtime-free) — a covered runner returns *BehaviorError (satisfies\n// error) instead of a bc-runtime failure, so the fully-covered module imports ZERO bc runtime.\n${behaviorErrorType}`,
2924
2435
  decls ? `// Typed struct declarations (outType-derived; hash-dedup — shared type plan).\n${decls}` : undefined,
2925
2436
  `// Per-component CONCRETE input structs (fields = inputPorts; the consumer builds them natively —\n// no generic *Obj crosses the covered read boundary).\n${inStructs.join("\n\n")}`,
2926
- rowStructs.some((r) => r.trim().length > 0)
2927
- ? `// CONCRETE per-node handler-result row structs (typed fields = the node's outType; + error signal).\n${rowStructs.filter((r) => r.trim().length > 0).join("\n\n")}`
2928
- : undefined,
2929
- `// Per-component CONCRETE handler interfaces (one typed Node_* method per covered node).\n${handlerIfaces.join("\n\n")}`,
2930
- decodeFns.length
2931
- ? `// strict de-box wire seam — the consumer implements WireRow/WireList over its wire payload\n// (variant classification); the generated decodeWire_* owns strictness (required/optional, present/\n// absent, error assembly, fail-closed). Concrete probe structs — no boxed Value on the seam.\n${emitProbeWireTypes()}`
2932
- : undefined,
2933
- decodeFns.length
2934
- ? `// Generated strict de-box functions (per named record type; structured Error Value on mismatch).\n${decodeFns.join("\n\n")}`
2437
+ anyWire
2438
+ ? `// strict de-box wire seam — the consumer supplies CONCRETE ${wire.value} / ${wire.row} / ${wire.list}\n// types (variant classification) and the runner classifies each node result against the STATICALLY\n// declared type via their methods; the generated INLINE de-box owns strictness (required/optional,\n// present/absent, error assembly, fail-closed). bc emits only the probe RESULT structs — concrete data,\n// no boxed Value, no interface, no dictionary crosses the seam.\n${emitProbeWireTypes(wire)}`
2935
2439
  : undefined,
2936
2440
  elemCopiers.length
2937
2441
  ? `// Augmented map-element copiers (over element fields + the concrete into row — pure assignment).\n${elemCopiers.join("\n\n")}`
@@ -2972,32 +2476,21 @@ export function goTypedNativeObserve(ir, runtimeImport) {
2972
2476
  // decode the generic *Obj input into the CONCRETE In_<comp> struct (test glue — ONE decode at the
2973
2477
  // top, OUTSIDE the covered hot path; a REQUIRED declared input is present so an absent key is a
2974
2478
  // fail-closed decode error surfaced here, never on the native runner path).
2975
- return `\tif name == ${JSON.stringify(c.name)} {\n\t\tin, ierr := decode_${inStructName(c.name)}(input)\n\t\tif ierr != nil {\n\t\t\treturn nil, ierr\n\t\t}\n\t\ttv, err := ${runnerName(c.name)}(handlers, in)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn ${ser}, nil\n\t}`;
2479
+ return `\tif name == ${JSON.stringify(c.name)} {\n\t\tin, ierr := decode_${inStructName(c.name)}(input)\n\t\tif ierr != nil {\n\t\t\treturn nil, ierr\n\t\t}\n\t\ttv, err := ${runnerName(c.name)}(${handlerTypeName(c.name)}{handlers}, in)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn ${ser}, nil\n\t}`;
2976
2480
  })
2977
2481
  .join("\n");
2978
2482
  // input decoders (TEST glue): generic *Obj -> concrete In_<comp>. Scalar fields read the typed value
2979
2483
  // (a `.(T)` here is on the SDK/wire Value in the OBSERVE companion, never in the covered module).
2980
2484
  const inDecoders = native.map((c) => emitInDecoder(c, plan)).join("\n\n");
2981
- // does any covered read de-box a named record a componentRef record OR a map/fanout element row
2982
- // (→ the scripted handler returns a WireRow / []WireRow)?
2983
- const anyDeBox = native.some((c) => {
2984
- const tn = new Map();
2985
- for (const n of c.body)
2986
- if (!isControlGate(n))
2987
- tn.set(n.id, "map" in n ? mapNodeArrRef(n, plan) : deriveTypeRef(n.outType, plan));
2988
- return c.body.some((n) => {
2989
- if ("cond" in n)
2990
- return false;
2991
- if ("map" in n || "fanout" in n)
2992
- return mapFanoutElemDeBoxEligible(n, tn, plan);
2993
- return deBoxEligible(tn.get(n.id));
2994
- });
2995
- });
2996
- // scripted wire adapter (TEST glue): wraps a scripted bc Value as a WireRow/WireList and classifies each
2997
- // attribute's native type into a DynamoDB-flavored wire tag (S/N/BOOL/L/M/NULL). A real consumer
2998
- // implements WireRow over its own AttributeValue map; this exists only so the harness drives the
2999
- // generated de-box from the same scripted vectors run_behavior uses — so actualWireType observed in a
3000
- // mismatch is the PRODUCER tag (e.g. "N"), not the collapsed native type.
2485
+ // every covered node returns a WireValue the inline de-box classifies so the scripted wire adapter is
2486
+ // needed whenever any component has a handler node.
2487
+ const anyDeBox = native.some((c) => c.body.some((n) => !("cond" in n)));
2488
+ // scripted wire adapter (TEST glue): wraps a scripted bc Value as the CONCRETE WireValue / WireRow /
2489
+ // WireList (the in-package default seam types the covered module references) and classifies each datum's
2490
+ // native type into a DynamoDB-flavored wire tag (S/N/BOOL/L/M/NULL). A real consumer supplies its OWN
2491
+ // concrete WireValue over its AttributeValue payload; this exists only so the harness drives the
2492
+ // generated inline de-box from the same scripted vectors run_behavior uses — so actualWireType observed
2493
+ // in a mismatch is the PRODUCER tag (e.g. "N"), not the collapsed native type.
3001
2494
  const wireAdapter = anyDeBox
3002
2495
  ? `// ── scripted wire adapter (TEST glue) ──
3003
2496
  func scriptedWireTag(v ${PKG}.Value) string {
@@ -3076,7 +2569,7 @@ func probeRowVal(v ${PKG}.Value) RowProbe {
3076
2569
  return RowProbe{Kind: probeNull, ActualWireType: "NULL", Raw: "null"}
3077
2570
  }
3078
2571
  if o, ok := v.(*${PKG}.Obj); ok {
3079
- return RowProbe{Kind: probeGot, Got: scriptedWireRow{obj: o}, ActualWireType: "M"}
2572
+ return RowProbe{Kind: probeGot, Got: WireRow{obj: o}, ActualWireType: "M"}
3080
2573
  }
3081
2574
  return RowProbe{Kind: probeWrong, ActualWireType: scriptedWireTag(v), Raw: scriptedWireRaw(v)}
3082
2575
  }
@@ -3086,79 +2579,89 @@ func probeListVal(v ${PKG}.Value) ListProbe {
3086
2579
  return ListProbe{Kind: probeNull, ActualWireType: "NULL", Raw: "null"}
3087
2580
  }
3088
2581
  if a, ok := v.([]${PKG}.Value); ok {
3089
- return ListProbe{Kind: probeGot, Got: scriptedWireList{items: a}, ActualWireType: "L"}
2582
+ return ListProbe{Kind: probeGot, Got: WireList{items: a}, ActualWireType: "L"}
3090
2583
  }
3091
2584
  return ListProbe{Kind: probeWrong, ActualWireType: scriptedWireTag(v), Raw: scriptedWireRaw(v)}
3092
2585
  }
3093
2586
 
3094
- type scriptedWireRow struct {
3095
- obj *${PKG}.Obj
2587
+ // WireValue — the CONCRETE scripted node-result wire (the in-package default seam type the covered runner
2588
+ // classifies via As*). A top value is always present, so As* never observes Absent; a scripted null is a
2589
+ // nil Value → Null. A real consumer supplies its own concrete WireValue over its AttributeValue payload.
2590
+ type WireValue struct {
2591
+ v ${PKG}.Value
3096
2592
  }
3097
2593
 
3098
- func newScriptedWireRow(v ${PKG}.Value) WireRow {
3099
- o, _ := v.(*${PKG}.Obj)
3100
- return scriptedWireRow{obj: o}
2594
+ func (w WireValue) AsString() StringProbe { return probeStringVal(w.v) }
2595
+ func (w WireValue) AsNumber() NumberProbe { return probeNumberVal(w.v) }
2596
+ func (w WireValue) AsBool() BoolProbe { return probeBoolVal(w.v) }
2597
+ func (w WireValue) AsRow() RowProbe { return probeRowVal(w.v) }
2598
+ func (w WireValue) AsList() ListProbe { return probeListVal(w.v) }
2599
+
2600
+ // WireRow / WireList — the CONCRETE scripted wire map / array (the in-package default seam types), probed
2601
+ // per declared field / element by the generated inline de-box (their methods return bc's probe structs).
2602
+ type WireRow struct {
2603
+ obj *${PKG}.Obj
3101
2604
  }
3102
2605
 
3103
- func (w scriptedWireRow) field(name string) (${PKG}.Value, bool) {
2606
+ func (w WireRow) field(name string) (${PKG}.Value, bool) {
3104
2607
  if w.obj == nil {
3105
2608
  return nil, false
3106
2609
  }
3107
2610
  return w.obj.Get(name)
3108
2611
  }
3109
2612
 
3110
- func (w scriptedWireRow) Keys() []string {
2613
+ func (w WireRow) Keys() []string {
3111
2614
  if w.obj == nil {
3112
2615
  return nil
3113
2616
  }
3114
2617
  return w.obj.Keys
3115
2618
  }
3116
2619
 
3117
- func (w scriptedWireRow) ProbeString(field string) StringProbe {
2620
+ func (w WireRow) ProbeString(field string) StringProbe {
3118
2621
  if v, ok := w.field(field); ok {
3119
2622
  return probeStringVal(v)
3120
2623
  }
3121
2624
  return StringProbe{Kind: probeAbsent}
3122
2625
  }
3123
2626
 
3124
- func (w scriptedWireRow) ProbeNumber(field string) NumberProbe {
2627
+ func (w WireRow) ProbeNumber(field string) NumberProbe {
3125
2628
  if v, ok := w.field(field); ok {
3126
2629
  return probeNumberVal(v)
3127
2630
  }
3128
2631
  return NumberProbe{Kind: probeAbsent}
3129
2632
  }
3130
2633
 
3131
- func (w scriptedWireRow) ProbeBool(field string) BoolProbe {
2634
+ func (w WireRow) ProbeBool(field string) BoolProbe {
3132
2635
  if v, ok := w.field(field); ok {
3133
2636
  return probeBoolVal(v)
3134
2637
  }
3135
2638
  return BoolProbe{Kind: probeAbsent}
3136
2639
  }
3137
2640
 
3138
- func (w scriptedWireRow) ProbeRow(field string) RowProbe {
2641
+ func (w WireRow) ProbeRow(field string) RowProbe {
3139
2642
  if v, ok := w.field(field); ok {
3140
2643
  return probeRowVal(v)
3141
2644
  }
3142
2645
  return RowProbe{Kind: probeAbsent}
3143
2646
  }
3144
2647
 
3145
- func (w scriptedWireRow) ProbeList(field string) ListProbe {
2648
+ func (w WireRow) ProbeList(field string) ListProbe {
3146
2649
  if v, ok := w.field(field); ok {
3147
2650
  return probeListVal(v)
3148
2651
  }
3149
2652
  return ListProbe{Kind: probeAbsent}
3150
2653
  }
3151
2654
 
3152
- type scriptedWireList struct {
2655
+ type WireList struct {
3153
2656
  items []${PKG}.Value
3154
2657
  }
3155
2658
 
3156
- func (l scriptedWireList) Len() int { return len(l.items) }
3157
- func (l scriptedWireList) ElemString(i int) StringProbe { return probeStringVal(l.items[i]) }
3158
- func (l scriptedWireList) ElemNumber(i int) NumberProbe { return probeNumberVal(l.items[i]) }
3159
- func (l scriptedWireList) ElemBool(i int) BoolProbe { return probeBoolVal(l.items[i]) }
3160
- func (l scriptedWireList) ElemRow(i int) RowProbe { return probeRowVal(l.items[i]) }
3161
- func (l scriptedWireList) ElemList(i int) ListProbe { return probeListVal(l.items[i]) }
2659
+ func (l WireList) Len() int { return len(l.items) }
2660
+ func (l WireList) ElemString(i int) StringProbe { return probeStringVal(l.items[i]) }
2661
+ func (l WireList) ElemNumber(i int) NumberProbe { return probeNumberVal(l.items[i]) }
2662
+ func (l WireList) ElemBool(i int) BoolProbe { return probeBoolVal(l.items[i]) }
2663
+ func (l WireList) ElemRow(i int) RowProbe { return probeRowVal(l.items[i]) }
2664
+ func (l WireList) ElemList(i int) ListProbe { return probeListVal(l.items[i]) }
3162
2665
 
3163
2666
  // FailureDetail exposes the structured Error Value fields WITHOUT naming the local ErrorDetail type, so
3164
2667
  // the harness can assert the de-box's kind / field / expectedType / actualWireType / rawValue (TEST
@@ -3171,21 +2674,17 @@ func (e *BehaviorError) FailureDetail() (kind, model, field, expectedType, actua
3171
2674
  return d.Kind, d.Model, d.Field, d.ExpectedType, d.ActualWireType, d.RawValue, true
3172
2675
  }`
3173
2676
  : "";
3174
- // The observe companion drives EVERY covered component, so its handler type param H must satisfy
3175
- // EVERY per-component concrete Handler_<comp> interface — a combined constraint embeds them all.
3176
- const combinedConstraint = `allNativeRawHandlers`;
3177
- const constraintDecl = `// ${combinedConstraint} the combined constraint embedding every covered component's concrete
3178
- // handler interface, so one handler value drives all covered runners (test glue only).
3179
- type ${combinedConstraint} interface {
3180
- ${native.map((c) => `\t${handlerIfaceName(c.name)}`).join("\n")}
3181
- }`;
3182
- // ── concrete scripted adapter (TEST glue): implements every Node_* method by draining a per-
3183
- // COMPONENT scripted-outcome queue and DECODING the scripted ok Value into the CONCRETE row struct.
3184
- // This is where the generic scripted source (a Value queue) meets the concrete per-node seam: the
3185
- // decode is generated (it knows the concrete row type), so the runner stays fully concrete. ──
3186
- const decodeFns = [];
2677
+ // Handler_<comp> wrapper types: the covered runner takes the CONCRETE per-component handler by value
2678
+ // (non-generic). One scripted queue backs every component, so each Handler_<comp> embeds the shared
2679
+ // *ScriptedNativeRaw the Node_* methods (on *ScriptedNativeRaw) are promoted, so the runner's direct
2680
+ // h.Node_*(...) call resolves to a concrete method (no interface, no dictionary). Test glue only.
2681
+ const handlerWrappers = native
2682
+ .map((c) => `// ${handlerTypeName(c.name)} the CONCRETE handler the '${c.name}' runner takes by value (embeds the\n// shared scripted queue; the Node_* methods are promoted).\ntype ${handlerTypeName(c.name)} struct {\n\t*ScriptedNativeRaw\n}`)
2683
+ .join("\n\n");
2684
+ // ── concrete scripted adapter (TEST glue): implements every Node_* method by draining a per-COMPONENT
2685
+ // scripted-outcome queue and returning the scripted ok Value wrapped as a WireValue (the generic
2686
+ // scripted source a Value queue meets the uniform CONCRETE wire seam). ──
3187
2687
  const methodImpls = [];
3188
- const emittedDecode = new Set();
3189
2688
  for (const c of native) {
3190
2689
  const typedNodes = new Map();
3191
2690
  for (const n of c.body)
@@ -3196,16 +2695,12 @@ ${native.map((c) => `\t${handlerIfaceName(c.name)}`).join("\n")}
3196
2695
  continue; // #108: cond has no handler method (pure Expression) — no scripted impl.
3197
2696
  const ref = typedNodes.get(n.id);
3198
2697
  if ("fanout" in n) {
2698
+ // fanout: return the aligned per-id element WIRES ([]*WireValue); a null aligned body is a
2699
+ // DANGLING id → nil (the covered runner maps it to the zero element).
3199
2700
  const f = n.fanout;
3200
- const elemDeBox = mapFanoutElemDeBoxEligible(n, typedNodes, plan);
3201
- const elemT = rawElemStructName(c.name, n.id);
3202
- const batchT = rawRowStructName(c.name, n.id);
3203
2701
  const portsT = `${portsStructName(c.name, n.id)}_batch`;
3204
2702
  const foBoundT = boundGoType(n, c, typedNodes, plan);
3205
- if (elemDeBox) {
3206
- // a record-element fanout returns the aligned element WIRES; the covered runner de-boxes each.
3207
- // A null aligned body is a DANGLING id — a nil wire (the runner maps it to the zero elem row).
3208
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${foBoundT}) ([]WireRow, error) {
2703
+ methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${foBoundT}) ([]*WireValue, error) {
3209
2704
  src, ok := s.next(${JSON.stringify(f.component)})
3210
2705
  if !ok {
3211
2706
  return nil, unknownComponent(${JSON.stringify(f.component)})
@@ -3214,54 +2709,27 @@ ${native.map((c) => `\t${handlerIfaceName(c.name)}`).join("\n")}
3214
2709
  return nil, leafFailure(src.err)
3215
2710
  }
3216
2711
  arr, _ := src.ok.([]${PKG}.Value)
3217
- wires := make([]WireRow, 0, len(arr))
2712
+ wires := make([]*WireValue, 0, len(arr))
3218
2713
  for _, ev := range arr {
3219
2714
  if ev == nil {
3220
2715
  wires = append(wires, nil)
3221
2716
  continue
3222
2717
  }
3223
- wires = append(wires, newScriptedWireRow(ev))
2718
+ wv := WireValue{v: ev}
2719
+ wires = append(wires, &wv)
3224
2720
  }
3225
2721
  return wires, nil
3226
- }`);
3227
- continue;
3228
- }
3229
- const elemRowRef = fanoutItemsElemRef(n, ref, plan);
3230
- const elemDecode = emitDecodeRow(c.name, n.id, elemT, elemRowRef, plan, emittedDecode, decodeFns, "Elem");
3231
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${foBoundT}) (${batchT}, error) {
3232
- src, ok := s.next(${JSON.stringify(f.component)})
3233
- if !ok {
3234
- return ${batchT}{}, unknownComponent(${JSON.stringify(f.component)})
3235
- }
3236
- if src.isErr {
3237
- return ${batchT}{}, leafFailure(src.err)
3238
- }
3239
- arr, _ := src.ok.([]${PKG}.Value)
3240
- rows := make([]${elemT}, 0, len(arr))
3241
- for _, ev := range arr {
3242
- if ev == nil {
3243
- rows = append(rows, ${elemT}{})
3244
- continue
3245
- }
3246
- rows = append(rows, ${elemDecode}(ev))
3247
- }
3248
- return ${batchT}{Rows: rows}, nil
3249
2722
  }`);
3250
2723
  continue;
3251
2724
  }
3252
2725
  if ("map" in n) {
2726
+ // map: batched → one WIRE per element ([]WireValue); non-batched → one element WIRE (WireValue).
3253
2727
  const m = n.map;
3254
2728
  const batched = m.batched === true;
3255
- const arrRef = ref;
3256
- const elemDeBox = mapFanoutElemDeBoxEligible(n, typedNodes, plan);
3257
- const elemT = rawElemStructName(c.name, n.id);
3258
- const batchT = rawRowStructName(c.name, n.id);
3259
2729
  const portsT = batched ? `${portsStructName(c.name, n.id)}_batch` : portsStructName(c.name, n.id);
3260
2730
  const mapBoundT = boundGoType(n, c, typedNodes, plan);
3261
- if (elemDeBox) {
3262
- // a record-element map returns the element WIRE(s); the covered runner de-boxes each strictly.
3263
- if (batched) {
3264
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) ([]WireRow, error) {
2731
+ if (batched) {
2732
+ methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) ([]WireValue, error) {
3265
2733
  src, ok := s.next(${JSON.stringify(m.component)})
3266
2734
  if !ok {
3267
2735
  return nil, unknownComponent(${JSON.stringify(m.component)})
@@ -3270,155 +2738,74 @@ ${native.map((c) => `\t${handlerIfaceName(c.name)}`).join("\n")}
3270
2738
  return nil, leafFailure(src.err)
3271
2739
  }
3272
2740
  arr, _ := src.ok.([]${PKG}.Value)
3273
- wires := make([]WireRow, 0, len(arr))
2741
+ wires := make([]WireValue, 0, len(arr))
3274
2742
  for _, ev := range arr {
3275
- wires = append(wires, newScriptedWireRow(ev))
2743
+ wires = append(wires, WireValue{v: ev})
3276
2744
  }
3277
2745
  return wires, nil
3278
- }`);
3279
- }
3280
- else {
3281
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) (WireRow, error) {
3282
- src, ok := s.next(${JSON.stringify(m.component)})
3283
- if !ok {
3284
- return nil, unknownComponent(${JSON.stringify(m.component)})
3285
- }
3286
- if src.isErr {
3287
- return nil, leafFailure(src.err)
3288
- }
3289
- return newScriptedWireRow(src.ok), nil
3290
- }`);
3291
- }
3292
- continue;
3293
- }
3294
- const elemRowRef = mapElemRowRef(n, arrRef, plan);
3295
- const elemDecode = emitDecodeRow(c.name, n.id, elemT, elemRowRef, plan, emittedDecode, decodeFns, "Elem");
3296
- if (batched) {
3297
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) (${batchT}, error) {
3298
- src, ok := s.next(${JSON.stringify(m.component)})
3299
- if !ok {
3300
- return ${batchT}{}, unknownComponent(${JSON.stringify(m.component)})
3301
- }
3302
- if src.isErr {
3303
- return ${batchT}{}, leafFailure(src.err)
3304
- }
3305
- arr, _ := src.ok.([]${PKG}.Value)
3306
- rows := make([]${elemT}, 0, len(arr))
3307
- for _, ev := range arr {
3308
- rows = append(rows, ${elemDecode}(ev))
3309
- }
3310
- return ${batchT}{Rows: rows}, nil
3311
2746
  }`);
3312
2747
  }
3313
2748
  else {
3314
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) (${elemT}, error) {
2749
+ methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, n.id)}(_ ${portsT}, _ ${mapBoundT}) (WireValue, error) {
3315
2750
  src, ok := s.next(${JSON.stringify(m.component)})
3316
2751
  if !ok {
3317
- return ${elemT}{}, unknownComponent(${JSON.stringify(m.component)})
2752
+ return WireValue{}, unknownComponent(${JSON.stringify(m.component)})
3318
2753
  }
3319
2754
  if src.isErr {
3320
- return ${elemT}{}, leafFailure(src.err)
2755
+ return WireValue{}, leafFailure(src.err)
3321
2756
  }
3322
- return ${elemDecode}(src.ok), nil
2757
+ return WireValue{v: src.ok}, nil
3323
2758
  }`);
3324
2759
  }
3325
2760
  continue;
3326
2761
  }
2762
+ // componentRef: return the whole result WIRE (one WireValue wrapping the scripted ok Value); the
2763
+ // covered runner's INLINE de-box classifies it. A real consumer returns its own wire payload.
3327
2764
  const node = n;
3328
- const rowT = rawRowStructName(c.name, node.id);
3329
2765
  const nodeBoundT = boundGoType(node, c, typedNodes, plan);
3330
- // a de-box-eligible node's scripted handler returns a scriptedWireRow (the scripted Value
3331
- // wrapped as a WireRow that classifies each attribute's native type into a DynamoDB-flavored wire
3332
- // tag); the covered module's generated decodeWire_* then probes it. This mirrors a real consumer,
3333
- // whose handler returns its wire payload for BC to de-box — the de-box no longer lives here.
3334
- if (deBoxEligible(ref)) {
3335
- // a record-containing top returns its wire (WireRow / []WireRow / nilable WireRow /
3336
- // map[string]WireRow) the covered runner de-boxes each record. #129: an arr node with an `items`
3337
- // port echoes the NATIVE port array; it is serialized back to []WireRow so the de-box round-trips.
3338
- const top = recordTop(ref);
3339
- const wireT = goWireTypeForTop(top);
3340
- // echo-into-record (#141 fixtures): a named de-box node whose result WRAPS an input port — the
3341
- // scripted leaf echoes port P into the record's single field, so the input-port value flows into
3342
- // the de-boxed result and the runtime non-vacuity #139/#143/#144 assert survives the record wrap.
3343
- let namedEcho = "";
3344
- if (top.kind === "named") {
3345
- const decl = findDecl(plan, top.innerName);
3346
- const recordGo = renderTypeRef(ref);
3347
- // a SINGLE-field record admits a scalar-into-field wrap (echo:port + wrap:"v" → {v: ports.X}).
3348
- const field = decl !== undefined && decl.fields.length === 1 ? decl.fields[0] : undefined;
3349
- const fieldGo = field !== undefined ? renderTypeRef(field.type) : null;
3350
- for (const pn of Object.keys(node.ports)) {
3351
- let portGo = null;
3352
- try {
3353
- portGo = portFieldGoType(node.ports[pn], c, plan, typedNodes, `echo port '${pn}'`);
3354
- }
3355
- catch {
3356
- portGo = null;
3357
- }
3358
- if (portGo === recordGo) {
3359
- // case 2: the port IS the whole record (its type == the node's record type) → echo it
3360
- // DIRECTLY (no field wrap), matching run_behavior's plain echo:port of a whole-record port.
3361
- namedEcho += `\tif src.echo == ${JSON.stringify(pn)} {\n\t\treturn newScriptedWireRow(${serializeTyped(`ports.${goPortFieldName(pn)}`, ref, plan)}), nil\n\t}\n`;
3362
- }
3363
- else if (fieldGo !== null && field !== undefined && portGo === fieldGo) {
3364
- // case 1: a scalar port wraps into the record's single field ({v: ports.X}).
3365
- namedEcho += `\tif src.echo == ${JSON.stringify(pn)} {\n\t\treturn newScriptedWireRow(${serializeTyped(`${recordGo}{${goFieldName(field.name)}: ports.${goPortFieldName(pn)}}`, ref, plan)}), nil\n\t}\n`;
3366
- }
2766
+ // echo (#129/#141 fixtures): the scripted leaf can ECHO an input PORT back as its result wire, so the
2767
+ // input-port value flows into the de-boxed result and the runtime non-vacuity asserts survive.
2768
+ const echoBranches = [];
2769
+ if (ref.kind === "named") {
2770
+ const decl = findDecl(plan, ref.name);
2771
+ const field = decl !== undefined && decl.fields.length === 1 ? decl.fields[0] : undefined;
2772
+ const fieldGo = field !== undefined ? renderTypeRef(field.type) : null;
2773
+ const recordGo = renderTypeRef(ref);
2774
+ for (const pn of Object.keys(node.ports)) {
2775
+ let portGo = null;
2776
+ try {
2777
+ portGo = portFieldGoType(node.ports[pn], c, plan, typedNodes, `echo port '${pn}'`);
2778
+ }
2779
+ catch {
2780
+ portGo = null;
2781
+ }
2782
+ if (portGo === recordGo) {
2783
+ // the port IS the whole record echo it DIRECTLY (matching run_behavior's plain echo:port).
2784
+ echoBranches.push(`\tif src.echo == ${JSON.stringify(pn)} {\n\t\treturn WireValue{v: ${serializeTyped(`ports.${goPortFieldName(pn)}`, ref, plan)}}, nil\n\t}`);
2785
+ }
2786
+ else if (fieldGo !== null && field !== undefined && portGo === fieldGo) {
2787
+ // a scalar port wraps into the record's single field ({v: ports.X}).
2788
+ echoBranches.push(`\tif src.echo == ${JSON.stringify(pn)} {\n\t\treturn WireValue{v: ${serializeTyped(`${recordGo}{${goFieldName(field.name)}: ports.${goPortFieldName(pn)}}`, ref, plan)}}, nil\n\t}`);
3367
2789
  }
3368
2790
  }
3369
- const canEcho = (top.kind === "arr" && Object.prototype.hasOwnProperty.call(node.ports, "items")) || namedEcho !== "";
3370
- const portsParam = canEcho ? "ports" : "_";
3371
- let body;
3372
- if (top.kind === "named") {
3373
- body = `${namedEcho}\treturn newScriptedWireRow(src.ok), nil`;
3374
- }
3375
- else if (top.kind === "arr") {
3376
- const elemRef = ref.elem;
3377
- const itemsF = goPortFieldName("items");
3378
- const echoBranch = canEcho
3379
- ? `\tif src.echo == "items" {\n\t\twires := make([]WireRow, 0, len(ports.${itemsF}))\n\t\tfor i := range ports.${itemsF} {\n\t\t\twires = append(wires, newScriptedWireRow(${serializeTyped(`ports.${itemsF}[i]`, elemRef, plan)}))\n\t\t}\n\t\treturn wires, nil\n\t}\n`
3380
- : "";
3381
- body = `${echoBranch}\tarr, _ := src.ok.([]${PKG}.Value)\n\twires := make([]WireRow, 0, len(arr))\n\tfor _, ev := range arr {\n\t\twires = append(wires, newScriptedWireRow(ev))\n\t}\n\treturn wires, nil`;
3382
- }
3383
- else if (top.kind === "opt") {
3384
- body = `\tif src.ok == nil {\n\t\treturn nil, nil\n\t}\n\treturn newScriptedWireRow(src.ok), nil`;
3385
- }
3386
- else {
3387
- body = `\tobj, _ := src.ok.(*${PKG}.Obj)\n\twires := make(map[string]WireRow)\n\tif obj != nil {\n\t\tfor _, k := range obj.Keys {\n\t\t\twires[k] = newScriptedWireRow(obj.Vals[k])\n\t\t}\n\t}\n\treturn wires, nil`;
3388
- }
3389
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, node.id)}(${portsParam} ${portsStructName(c.name, node.id)}, _ ${nodeBoundT}) (${wireT}, error) {
3390
- src, ok := s.next(${JSON.stringify(node.component)})
3391
- if !ok {
3392
- return nil, unknownComponent(${JSON.stringify(node.component)})
3393
- }
3394
- if src.isErr {
3395
- return nil, leafFailure(src.err)
3396
- }
3397
- ${body}
3398
- }`);
3399
- continue;
3400
2791
  }
3401
- const decode = emitDecodeRow(c.name, node.id, rowT, ref, plan, emittedDecode, decodeFns, "");
3402
- // #129 (TEST glue): if this node has an `items` port and its outType is a bare arr, support the
3403
- // reference scriptedHandlers' `echo === "items"` — the scripted handler ECHOES the NATIVE `items`
3404
- // port back as its result. This makes the node→leaf array dataflow test non-vacuous: the leaf's
3405
- // observed result is exactly the native array that flowed into its ports struct, so a dropped or
3406
- // boxed native array would diverge from run_behavior. `ports` is named only when the echo path
3407
- // uses it (else the param stays `_` so a non-echo node compiles clean / unused-param-free).
3408
- const canEcho = ref.kind === "arr" && Object.prototype.hasOwnProperty.call(node.ports, "items");
2792
+ else if (ref.kind === "arr" && Object.prototype.hasOwnProperty.call(node.ports, "items")) {
2793
+ // #129: an arr node with an `items` port echoes the NATIVE port array (serialized to a Value array)
2794
+ // so the node→leaf array dataflow test is non-vacuous.
2795
+ echoBranches.push(`\tif src.echo == "items" {\n\t\treturn WireValue{v: ${serializeTyped(`ports.${goPortFieldName("items")}`, ref, plan)}}, nil\n\t}`);
2796
+ }
2797
+ const canEcho = echoBranches.length > 0;
3409
2798
  const portsParam = canEcho ? "ports" : "_";
3410
- const echoBranch = canEcho
3411
- ? `\tif src.echo == "items" {\n\t\treturn ${rowT}{Val: ports.${goPortFieldName("items")}}, nil\n\t}\n`
3412
- : "";
3413
- methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, node.id)}(${portsParam} ${portsStructName(c.name, node.id)}, _ ${nodeBoundT}) (${rowT}, error) {
2799
+ const echoBlock = canEcho ? `${echoBranches.join("\n")}\n` : "";
2800
+ methodImpls.push(`func (s *ScriptedNativeRaw) ${nodeMethodName(c.name, node.id)}(${portsParam} ${portsStructName(c.name, node.id)}, _ ${nodeBoundT}) (WireValue, error) {
3414
2801
  src, ok := s.next(${JSON.stringify(node.component)})
3415
2802
  if !ok {
3416
- return ${rowT}{}, unknownComponent(${JSON.stringify(node.component)})
2803
+ return WireValue{}, unknownComponent(${JSON.stringify(node.component)})
3417
2804
  }
3418
2805
  if src.isErr {
3419
- return ${rowT}{}, leafFailure(src.err)
2806
+ return WireValue{}, leafFailure(src.err)
3420
2807
  }
3421
- ${echoBranch} return ${decode}(src.ok), nil
2808
+ ${echoBlock} return WireValue{v: src.ok}, nil
3422
2809
  }`);
3423
2810
  }
3424
2811
  }
@@ -3433,10 +2820,10 @@ type scriptSrc struct {
3433
2820
  ok ${PKG}.Value
3434
2821
  }
3435
2822
 
3436
- // ScriptedNativeRaw — the CONCRETE test handler: it satisfies every Handler_<comp> interface by
3437
- // draining a per-COMPONENT scripted queue and decoding the ok Value into the concrete row struct.
3438
- // The decode (decodeRow_*) is generated, so the covered runner drives fully-concrete Node_* methods.
3439
- // EXPORTED so the runner glue (a separate package) can name it for the generic instantiation.
2823
+ // ScriptedNativeRaw — the CONCRETE test handler: its Node_* methods drain a per-COMPONENT scripted queue
2824
+ // and return the ok Value wrapped as a WireValue (the covered runner de-boxes it inline). Each runner
2825
+ // takes a Handler_<comp> value that embeds this, so the Node_* calls stay fully concrete (no interface).
2826
+ // EXPORTED so the runner glue (a separate package) can name it.
3440
2827
  type ScriptedNativeRaw struct {
3441
2828
  mu sync.Mutex
3442
2829
  queues map[string][]scriptSrc
@@ -3510,10 +2897,10 @@ func (s *ScriptedNativeRaw) next(component string) (scriptSrc, bool) {
3510
2897
  }`;
3511
2898
  return `// GENERATED test-only observe companion (bc#77) — NOT part of the covered module. Serializes the
3512
2899
  // struct-native runner's result to a canonical Value for the equivalence pin, and carries the CONCRETE
3513
- // scripted test handler (scriptedNativeRaw) that satisfies every Handler_<comp> interface by decoding a
3514
- // scripted Value into the concrete per-node row. The consumer never uses this (it keeps the model
3515
- // native + implements Handler_<comp> over its own wire payload); it exists only so the test harness can
3516
- // byte-compare the STRUCT-only covered read against run_behavior. Same package as the covered module.
2900
+ // scripted test handler (ScriptedNativeRaw) + the CONCRETE WireValue/WireRow/WireList seam types +
2901
+ // per-component Handler_<comp> wrappers the runner takes. The consumer never uses this (it keeps the
2902
+ // model native + supplies its own concrete WireValue + Handler_<comp>); it exists only so the test
2903
+ // harness can byte-compare the STRUCT-only covered read against run_behavior. Same package as the module.
3517
2904
  package behaviors
3518
2905
 
3519
2906
  import (
@@ -3522,69 +2909,40 @@ ${anyDeBox ? '\t"strconv"\n\n' : ""} "sync"
3522
2909
  ${PKG} "${runtimeImport ?? "github.com/foo-ogawa/behavior-contracts/go"}"
3523
2910
  )
3524
2911
 
3525
- // scripted wire adapter (TEST glue) — wraps a scripted Value as a WireRow the generated de-box probes.
2912
+ // scripted wire adapter (TEST glue) — the CONCRETE WireValue/WireRow/WireList the covered module references.
3526
2913
  ${wireAdapter}
3527
2914
 
3528
2915
  // typed -> Value serializers (TEST glue only — the covered module has none).
3529
2916
  ${serializers}
3530
2917
 
3531
- // Value -> typed struct marshallers (+ must* helpers) for the concrete-row decode (TEST glue only).
2918
+ // Value -> typed struct marshallers (+ must* helpers) for the input decoders (TEST glue only).
3532
2919
  ${marshallers}
3533
2920
 
3534
2921
  ${mustHelpers}
3535
2922
 
3536
2923
  ${arrOptHelpers}
3537
2924
 
3538
- // per-node concrete-row decoders (scripted Value -> RawRow_/RawElem_ struct).
3539
- ${decodeFns.join("\n\n")}
3540
-
3541
2925
  // input decoders (generic *Obj -> concrete In_<comp>; TEST glue, one decode at the observe boundary).
3542
2926
  ${inDecoders}
3543
2927
 
3544
2928
  ${adapter}
3545
2929
 
3546
- ${constraintDecl}
2930
+ // per-component CONCRETE handler wrappers (the runner takes one by value — embeds the shared queue).
2931
+ ${handlerWrappers}
3547
2932
 
3548
- // scriptedNativeRaw method impls (one per covered node — the concrete Node_* seam, test glue).
2933
+ // ScriptedNativeRaw method impls (one per covered node — the concrete Node_* seam returning WireValue).
3549
2934
  ${methodImpls.join("\n\n")}
3550
2935
 
3551
- // ObserveNativeRaw drives the struct-native runner and serializes to a canonical Value (test only).
3552
- // GENERIC over the CONCRETE combined handler type H so each enclosed RunNativeRawStruct_* call is
3553
- // instantiated at the concrete handler type (direct, devirtualized per-node method calls), not at an
3554
- // interface. Instantiate with your concrete handler type to preserve the covered path's concreteness.
3555
- func ObserveNativeRaw[H ${combinedConstraint}](name string, handlers H, input *${PKG}.Obj) (${PKG}.Value, error) {
2936
+ // ObserveNativeRaw drives the struct-native runner and serializes to a canonical Value (test only). It
2937
+ // takes the CONCRETE *ScriptedNativeRaw and wraps it per component in the runner's Handler_<comp> value —
2938
+ // each enclosed RunNativeRawStruct_* call is a NON-generic call over a concrete handler (direct,
2939
+ // devirtualized per-node method calls), never an interface or a generic dictionary.
2940
+ func ObserveNativeRaw(name string, handlers *ScriptedNativeRaw, input *${PKG}.Obj) (${PKG}.Value, error) {
3556
2941
  ${arms}
3557
2942
  return nil, ${PKG}.NewBehaviorFailure("UNKNOWN_ENTRY", "component '"+name+"' is not a covered read (fail-closed)")
3558
2943
  }
3559
2944
  `;
3560
2945
  }
3561
- /** emitDecodeRow — emit (once, deduped) a decoder `decodeRow_<comp>_<node><suffix>(v Value) <rowT>`
3562
- * that materializes the scripted ok Value into the concrete row struct (typed fields = the outType /
3563
- * elem-row type). Named: reuse the Value->struct marshaller + copy fields; scalar/arr/opt: materialize
3564
- * into .Val. TEST glue only (the production consumer decodes its own wire payload). */
3565
- function emitDecodeRow(compName, nodeId, rowT, ref, plan, emitted, out, suffix) {
3566
- const fn = `decodeRow_${sanitize(compName)}_${nodeId.replace(/[^A-Za-z0-9_]/g, "_")}${suffix}`;
3567
- if (emitted.has(fn))
3568
- return fn;
3569
- emitted.add(fn);
3570
- const lines = [];
3571
- lines.push(`func ${fn}(v ${PKG}.Value) ${rowT} {`);
3572
- lines.push(`\tvar out ${rowT}`);
3573
- if (ref.kind === "named") {
3574
- const decl = findDecl(plan, ref.name);
3575
- lines.push(`\tt := ${goTypedInternals.materializeExpr("v", ref, plan)}`);
3576
- for (const f of decl.fields) {
3577
- lines.push(`\tout.${goFieldName(f.name)} = t.${goFieldName(f.name)}`);
3578
- }
3579
- }
3580
- else {
3581
- lines.push(`\tout.Val = ${goTypedInternals.materializeExpr("v", ref, plan)}`);
3582
- }
3583
- lines.push(`\treturn out`);
3584
- lines.push(`}`);
3585
- out.push(lines.join("\n"));
3586
- return fn;
3587
- }
3588
2946
  /**
3589
2947
  * goTypedNativeEmitter — language id `go-typed-native` (bc#77). Emits the generic straight-line
3590
2948
  * body (for non-covered components / helpers) plus the COMBINED READ layer (native ports struct