OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb commits / b86ccde

skills/blender-bridge + proc-nodes: measured state at v0.80.0, and the sentence that became an argument
Both skills were written at blender-bridge v0.61.0 / proc-nodes' pre-edge-domain state and hyper-games #62 and #63 have since moved everything they assert. Every number here was produced today by running the thing, not by copying the issues: the three audits, all 54 test_*.py, the socket dump, and greps of the two trees. The one that mattered: blender-bridge/SKILL.md said the two zone CUSTOM sockets "may not be representable, so the realistic floor is 2, not 0". Never measured, and #63 Part 3 records it being repeated to the user as a claim about multi-inputs and item lists. UNRESOLVED is 0. The instrument had been wrong three ways at once. That correction is now written where the number was. Measured, blender-bridge: - coverage 101/360 (28.1%), sockets by NAME 279/90.3%, by INDEX 25, GODOT-ONLY 5, UNRESOLVED 0 - ledger 5 of 101 types -- and NOT "all UV Map outputs" as #63 says: MeshCylinder is 1 < 5, also missing Top, Side, Bottom - 46 of 54 test files print a result line: 1138 assertions, 0 failed - terrain end to end: correlation 1.000000, RMS 1.967e-07, median 3.553e-15 - test_blender_godot_bridge.py is RED and flaky -- 6/3, 6/3, 8/1 over three runs, Godot-side aborts, output_defaults failing every time; it also runs stock godot4 4.6 from PATH while everything else uses the 4.7 custom build. Recorded under Known Issues rather than left inside "all green" - test_ptex_converter.py SKIPS for want of pytest; it is not passing Measured, proc-nodes: - 119 node types (132 GDREGISTER_CLASS lines include the data classes) - edges are DERIVED via compute_edges(), face_offsets is load-bearing, only MeshGrid emits quads, Selection is on 24 node types, ExtrudeMesh produces a per-face field - SocketDef.multi is a socket KIND; item lists carry CD_PROP codes on one side and socket-type strings on the other - a zone body is an INTERSECTION, and connect_sockets' new bounds check replaced a segfault that had always been latent - the GLSL debt named per file:line -- 9 nodes GPU-off on purpose -- with the instrument constraint that only the standalone -lvulkan gate can see it Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b86ccdea797ce792e0c93ce6bf50b6eb89ec52b6
by plankatron <fleeky@gmail.com> · 2026-09-05T19:51:06.000Z

Changed files (2) +235 -39

.claude/skills/blender-bridge/SKILL.md +130 -18
……@@ -10,8 +10,12 @@ Two systems in one repo, and it matters which one you are in:
1010 identically in-game. Lives in `blender_addon/geometry_deserializer.py` and
1111 `test/`. **This is the active work** and has its own section below.
1212
13**Verified 2026-09-04** against v0.58.0, Blender 5.2.0, Godot 4.7.beta custom.
14Everything dated here was measured on that day; anything older is marked.
13**Verified 2026-09-05** against v0.80.0, Blender 5.2.0 (`fbe6228777e7`), Godot
144.7.beta custom `3bb2c0245`. Every number below was produced by RUNNING the
15thing on that day — the audits, all 54 test files, the terrain end-to-end — and
16anything older is marked. The previous revision of this file quoted a socket
17floor it had not measured, and that sentence became the argument for a wrong
18claim to the user (hyper-games #63 Part 3). Re-run, do not quote.
1519
1620## MANDATORY: Version Bump on EVERY Change
1721
……@@ -21,8 +25,9 @@ Everything dated here was measured on that day; anything older is marked.
21253. Rebuild C++ AFTER the bump — **all three targets**, see Build
22264. .so is **symlinked** to hyper-tps (no copy needed)
2327
24**Current version: 0.61.0** (branch: `sdf-volume-bridge`, 26 commits unpushed
25to `bare` as of 2026-09-04)
28**Current version: 0.80.0** (branch: `sdf-volume-bridge`, HEAD `d0efc30`,
29**49 commits unpushed** to `bare` as of 2026-09-05; proc-nodes carries 38 of its
30own on `heightmap-erosion-toggle`, HEAD `be03703`)
2631
2732## Where things are
2833
……@@ -243,6 +248,37 @@ point domain 3 verts / 0 tris, face domain 6 verts / 4 tris.
243248Consequence: `Position`, `Normal` and `NamedAttribute` no longer take a Geometry
244249input, matching Blender.
245250
251## What v0.62.0 -> v0.80.0 closed (hyper-games #62, #63)
252
253Measured 2026-09-05, not quoted:
254
255- **The ledger is 5 of 101 mapped types**, down from 52. All five are mesh
256 primitives (`audit_missing_sockets.py` prints them). ⚠ #63 says "all of them
257 UV Map outputs" — the audit says otherwise: `MeshCylinder` is `1 < 5`, missing
258 **Top, Side, Bottom** as well as UV Map. The other four are UV Map alone.
259- **UNRESOLVED is 0.** The five remaining unmatched proc sockets are GODOT-ONLY
260 and deliberate: kept AFTER Blender's last socket so they cannot displace a
261 real one, and unreachable by any Blender index.
262- **A multi-input socket is a KIND, not a workaround.** `SocketDef.multi`
263 (`proc-nodes/src/graph/proc_node.h`). Join Geometry's "Geometry A"/"Geometry B"
264 pair is gone. It took TWO fixes — the kind, and the serializer, which emitted
265 one connection per input socket and followed `links[0]`, so the extra links
266 were lost before proc-nodes ever saw them.
267- **Item lists cross.** Capture Attribute has one, the repeat and simulation
268 zones one each on their OUTPUT node, Foreach has three (`input_items`,
269 `main_items`, `generation_items`). Two vocabularies, NOT interchangeable: an
270 item reports `data_type` as a CD_PROP code (FLOAT_VECTOR 48) while
271 `capture_items.new()` takes a socket-type STRING ('VECTOR').
272- **The edge and corner domains are real**, and `face_offsets` is load-bearing:
273 `ProcMesh::compute_edges()`, `has_ngons()`. Only `MeshGrid` emits quads so far.
274- **A per-face field has a producer**: Extrude Mesh writes Top/Side on
275 `AttrDomain::Face`. A `Selection` input now exists on **24** node types
276 (measured from the socket dump), where the old note here listed six that
277 lacked one.
278- **Ramp and curve DATA cross both ways**, per element: Colour Ramp 298/298
279 (worst 4.718e-16), Float Curve 121/121 (4.885e-15), RGB Curves 17/17
280 (4.441e-15), plus 26/32/5 on the three crossing suites.
281
246282## Traps recorded here so they are not rediscovered
247283
248284- **`SocketValue::to_float()` takes `vec.x`** from a non-field scalar, so a
……@@ -257,7 +293,24 @@ input, matching Blender.
257293 ate hyper-tps' 30-line Jolt experiment block twice. `hyper-tps/scripts/dev-editor.sh`
258294 now restores it when the editor changed no setting.
259295- **A build guard that compares mtimes is unsound** — scons keys on content, so
260 it cries wolf on a clean tree.
296 it cries wolf on a clean tree. Same shape: `git checkout --` on an UNTRACKED
297 file restores nothing and `git diff --quiet` is vacuous on one, so a mutation
298 sweep guarded that way reports "unchanged" for every mutation and skips every
299 build. Guard on relink time as well as file change.
300- **On a Blender socket, a `default_value` is a UI affordance until proven
301 otherwise.** Implicit-field sockets IGNORE it and Blender substitutes the
302 implicit field: texture `Vector`, Scale Elements' `Center`, Random Value's
303 `ID`, Extrude Mesh's `Offset` (unconnected it is the NORMAL — setting the
304 default to (1,0,0) changes nothing, measured), Store Named Attribute's and
305 foreach's `Selection`. A harness that sweeps such a socket through its default
306 feeds Blender a number it never reads, and the NODE then looks wrong. Ask
307 `is_input_connected`. This trap has now cost time in #62 and three more times
308 in #63.
309- **`__extend__` is not a data socket.** It is Blender's affordance for growing
310 an item list and carries nothing. Counting it broke the socket audit AND the
311 serialized socket indices — the Foreach OUTPUT node has one in the MIDDLE,
312 between `main_items` and `generation_items`, so every index after it was one
313 too high.
261314- `graphs/terrain.tres` in hyper-tps has been **broken since 2026-03-27**: node 3
262315 is `null` while `connections` still references it, so it evaluates to no mesh.
263316 It took SlopeGradient's Slope into socket 2 — the same mis-wiring as the test
……@@ -265,8 +318,11 @@ input, matching Blender.
265318
266319## Post-mortems
267320
268`hyper-games` #60 (and its comment) is the full account, in the #41/#44/#45/#53/
269#55–#59 series. Read it before resuming parity work.
321The series is `hyper-games` #41/#44/#45/#53/#55–#63, newest first. **#63 and
322#62 are the two to read before resuming parity work**; #60 is the older full
323account. #63's own NEXT list is the queue: the GLSL debt (untouched), the five
324UV Map outputs, quads for the other six primitives, Merge By Distance Connected
325+ Edge Paths to Curves, and growing the map past 101/360.
270326
271327---
272328
……@@ -641,7 +697,21 @@ reach fingertips (Z already aligns with chain). Works for all leaf bones (breast
641697 now a SYMLINK to the source, so there is nothing to copy — but the restart is
642698 still required.
643699- **The C++ test suites do not build** — source only, no SConstruct targets
644- No known numerical gap in the terrain path as of v0.61.0
700- **`test/test_blender_godot_bridge.py` is RED and flaky** — the material-graph
701 integration suite, the SCENE-SYNC half, not parity. Measured over three runs
702 2026-09-05: **6/3, 6/3, 8/1**. The failures are Godot-side aborts (`signal 11`
703 in one run, `rc=-6` in another), so WHICH tests fail moves between runs; only
704 `output_defaults applied` failed all three, with `errs=[]` — the headless
705 subprocess printed neither `OK` nor `ERR:`. Not a timeout: the project starts
706 headless in **1.4 s** against the suite's 30 s budget. ⚠ It hardcodes
707 `GODOT_BIN = "godot4"`, which on PATH is **stock 4.6.stable**, while every
708 other cross-engine test uses the 4.7.beta custom build; forcing 4.7 with a
709 PATH shim changed which tests failed, not the count. Undiagnosed.
710- **`test/test_ptex_converter.py` SKIPS** — it imports `pytest`, which Blender's
711 bundled Python does not have. It is not passing; it is not running.
712- No known numerical gap in the terrain path as of v0.80.0: measured
713 2026-09-05, correlation **1.000000**, RMS **1.967e-07**, median residual
714 **3.553e-15** over 576 vertices, 0 vertices over 1% of the height span.
645715
646716## Testing
647717
……@@ -664,9 +734,24 @@ $BL --background --factory-startup --python test/test_rotation_matrix_values.py
664734$BL --background --factory-startup --python test/test_phacelle_parity.py # 7/7, 9.537e-07
665735$BL --background --factory-startup --python test/test_erosion_filter_parity.py # 6/6, 2.980e-08
666736$BL --background --factory-startup --python test/test_rotation_matrix_parity.py # 17/17
737
738# the whole thing — every file runs under Blender, ~20 min
739for f in test/test_*.py; do $BL --background --factory-startup --python $f; done
667740```
668741
669Counts and deltas above were **measured 2026-09-04**, all green.
742**Measured 2026-09-05 by running all 54 `test_*.py`:**
743
744| | |
745|---|---|
746| files that print a `N/N passed` line | **46 — 1138 assertions, 0 failed** |
747| biggest suites | color_ramp 298, float_curve 121, math_ops 71, random_value 62, map_range 49, material_serializer 41, node_primitives 40 |
748| files with their own dialect | 8 — see below |
749
750The 8: `erosion_noise_parity` **PASS** (identity orientation, corr 1.000000);
751`importer_coverage` *all 101 types build*; `python_shm` 11; `tile_baker` 26;
752`cross_language` all passed; `bench_tile_baker` is a benchmark and asserts
753nothing; `ptex_converter` **SKIPS** (no pytest); `blender_godot_bridge`
754**FAILS** — both under Known Issues.
670755
671756The C++ suites (`test_shm_protocol.cpp`, `test_uds.cpp`, `test_page_table.cpp`,
672757`test_tile_cache.cpp`, `test_tile_requests.cpp`, `test_validation.cpp`,
……@@ -687,20 +772,38 @@ $GODOT --headless --path ../proc-nodes/demo --script res://socket_dump.gd -- /tm
687772PROC_SOCKETS=/tmp/ps.json $BL --background --factory-startup --python test/audit_socket_names.py
688773```
689774
690Measured 2026-09-04, Blender 5.2.0:
775There is a third audit, the reverse of the second — which of BLENDER'S sockets
776have nowhere to land on our node:
777
778```bash
779PROC_SOCKETS=/tmp/ps.json $BL --background --factory-startup --python test/audit_missing_sockets.py
780```
781
782Measured 2026-09-05, Blender 5.2.0, proc-nodes `be03703`:
691783
692784| | |
693785|---|---|
694786| registered `bpy.types.Node` classes | 571 |
695787| **instantiable in a GeometryNodeTree** | **360** — the honest universe |
696| `GEOMETRY_NODE_MAP` entries | 98 (27.2%), 0 dead |
697| missing | 262 — other 79, curve 39, point/volume 35, mesh 35, input 27, string 13, field/utility 10, instance 7, attribute 6, texture 6, matrix/rotation 5 |
698| sockets by NAME | 174 (81.7%) |
699| sockets by INDEX (fallback) | 33 (15.5%) |
700| **UNRESOLVED** (dropped at runtime) | **6** — `CaptureAttribute:Value`, `CurveToMesh:Resolution`, `DistributePointsOnFaces:Count`, `JoinGeometry:Geometry B`, `RepeatZoneInput:Geometry`, `SimulationZoneInput:Geometry` |
701
702The last two are `CUSTOM` multi-sockets and may not be representable, so the
703realistic floor is 2, not 0.
788| offered in the add menu (>=) | 336 |
789| `GEOMETRY_NODE_MAP` entries | **101** (28.1%), 0 dead |
790| missing | 259 — other 77, curve 39, point/volume 35, mesh 35, input 26, string 13, field/utility 10, instance 7, attribute 6, texture 6, matrix/rotation 5 |
791| sockets by NAME | **279 (90.3%)** |
792| sockets by INDEX (fallback, type agrees) | 25 (8.1%) |
793| GODOT-ONLY (past Blender's last socket) | 5 (1.6%) — `CurveToMesh:Resolution,Closed`, `DistributePointsOnFaces:Count`, `RepeatZoneInput:Geometry`, `SimulationZoneInput:Geometry` |
794| **UNRESOLVED** (dropped at runtime) | **0** |
795| missing-socket ledger | **5 of 101 types** — `MeshCube`, `MeshGrid`, `MeshIcoSphere`, `MeshUVSphere` each missing `UV Map`; `MeshCylinder` `1 < 5`, also missing `Top`, `Side`, `Bottom` |
796
797⛔ **The old text here said the two zone `CUSTOM` sockets "may not be
798representable, so the realistic floor is 2, not 0".** That was never measured
799and it is wrong twice over. It became the argument for telling the user that
800multi-inputs and item lists could not be represented (#63 Part 3) — geometry
801nodes is the rosetta stone; everything is representable, as a nested group or at
802the bridge. And the instrument was wrong three ways: it counted `__extend__` as
803a data socket, its scratch tree had NO GROUP INTERFACE so Group Input/Output
804matched against nothing, and it reported deliberate Godot-only sockets as
805"dropped at runtime" when nothing addresses them. **Fix the measurement first;
806the number only means something afterwards.**
704807
705808**Do not filter Blender's sockets on `enabled`.** Blender hides sockets by MODE
706809— Noise Texture's `W` only in 4D, `Offset`/`Gain` only for multifractal types —
……@@ -727,3 +830,12 @@ number the tool got wrong.
727830 exactly, **GradientNoise parity 1.000000**
728831- 2026-09-04 (unversioned): coverage/socket audits, rotation-matrix parity
729832 across 18 nodes, and the erosion re-port down to `erosion_filter`
833- v0.62.0-v0.68.0 (#62): the bridged mountain crosses exactly (2582018 verts,
834 same bounds); nine node families ported from Blender's own source at 61a36e08
835 (hash, Voronoi, Noise Texture, Gradient Texture, Map Range, Math + Vector
836 Math, Mix, Wave + Vector Rotate, mesh primitives); the graph FRAME marked at
837 the bridge instead of converting values; ledger 52 -> 17
838- v0.68.0-v0.80.0 (#63): ramp and curve DATA both directions; the edge domain;
839 quads; multi-input as a socket kind; item lists and zone pairing; the
840 attribute family typed for all nine `data_type`s; ledger 17 -> 5, UNRESOLVED
841 6 -> 0, socket-by-name 81.7% -> 90.3%
.claude/skills/proc-nodes/SKILL.md +105 -21
……@@ -6,8 +6,9 @@ volumes and instances inside the Godot editor, compiles GPU-capable subgraphs
66to Vulkan compute, and exports a node graph as a standalone GLSL density
77function for dc-terrain.
88
9**Verified 2026-09-04** against Godot 4.7.beta custom, branch
10`heightmap-erosion-toggle`.
9**Verified 2026-09-05** against Godot 4.7.beta custom `3bb2c0245`, branch
10`heightmap-erosion-toggle` at `be03703`, **38 commits unpushed** to `bare`.
11Every count below was produced by running the dump or grepping the tree today.
1112
1213## When to Use
1314
……@@ -41,10 +42,12 @@ src/editor/ graph editor plugin
4142demo/ headless probe scripts (see Probes)
4243```
4344
44## Node count: 120 registered, 118 instantiable
45## Node count: 119 instantiable (2026-09-05)
4546
4647`README.md` says **59 node types**; it has been stale for a long time.
47Measured from `src/register_types.cpp` and `ClassDB`:
48`src/register_types.cpp` has 132 `GDREGISTER_CLASS` lines — that counts
49`ProcMesh`, `ProcCurves` and the rest of the data classes too. The node classes,
50counted per header and confirmed against the socket dump (119 types), are:
4851
4952| file | classes | | file | classes |
5053|---|---|---|---|---|
……@@ -53,7 +56,7 @@ Measured from `src/register_types.cpp` and `ClassDB`:
5356| math_nodes | 12 | | mesh_primitive_nodes | 7 |
5457| mesh_ops_nodes | 12 | | geometry_nodes | 6 |
5558| input_nodes | 9 | | zone_nodes | 6 |
56| instance_nodes | 5 | | selection_nodes | 5 |
59| instance_nodes | 5 | | selection_nodes | 6 |
5760| point_nodes | 3 | | volume_nodes | 3 |
5861| utility_nodes | 2 | | | |
5962
……@@ -82,6 +85,16 @@ a vector into a float socket and it reads as a near-constant that LOOKS
8285plausible; Blender averages x, y, z per point instead. That asymmetry hid a
8386mis-wired test scene for months and reads as "Blender has more detail".
8487
88**A socket also has a KIND.** `SocketDef.multi` (`graph/proc_node.h`) marks a
89MULTI-INPUT socket, which accepts any number of links in the order they were
90made — Blender's `is_multi_input`, used for Join Geometry, zone and capture item
91lists, and Group Output's growing interface. Without it a second link REPLACED
92the first, so a three-way join silently kept one, and our workaround (a discrete
93"Geometry B" socket) matched nothing on Blender's node. ⚠ The kind alone was not
94enough: blender-bridge's serializer emitted ONE connection per input socket and
95followed `links[0]`, so the other links were lost before proc-nodes saw them.
96Both sides, or the test stays at 1/4.
97
8598## Fields carry a domain, and producers are LAZY
8699
87100A field is an array **plus a statement of what it is per**. Without the domain
……@@ -108,18 +121,27 @@ removing `Position`'s input before deferral existed broke every chain through an
108121intermediate node, and then deferring on ANY lazy input caught `SetPosition`
109122itself.
110123
111**Still missing**: nothing PRODUCES a per-face field. `DeleteGeometry` consumes
112one via point->face interpolation, so the Face branch is proven only through
113interpolation. And `Selection` exists on `SetPosition` and `DeleteGeometry` but
114not on `MergeByDistance`, `ResampleCurve`, `TrimCurve`, `ExtrudeMesh`,
115`DuplicateElements`, `ScaleElements` — the largest remaining source of
116index-fallback socket resolution.
117
118**`ProcMesh` has no edge array** — positions, triangles, face offsets only. So
119`MeshLine` outputs a point cloud where Blender outputs a mesh, and the whole
120edge domain is unreachable. Tangents and `face_offsets` are DROPPED whenever
121`DeleteGeometry` changes topology (deliberate — wrong tangents are harder to
122notice than absent ones — but a real loss).
124⚠ **Superseded 2026-09-05** — this file used to say nothing produced a per-face
125field, that `Selection` existed on only two nodes, and that `ProcMesh` had no
126edges. Measured today:
127
128- **Per-face fields have a producer**: `ExtrudeMesh` writes Top and Side on
129 `AttrDomain::Face` (`mesh_ops_nodes.cpp:449-450`).
130- **`Selection` is on 24 node types** — every one the old note listed as lacking
131 it, plus the instance, curve and edge operations.
132- **Edges are DERIVED, not stored.** `ProcMesh` still carries positions,
133 triangles/corners and `face_offsets`, but `compute_edges()` builds the edge
134 array on demand (2 ints per edge, `v0 < v1`), so `domain_size(Edge)` is real
135 and the edge domain is selectable. ⚠ **Edge ORDER is ours, not Blender's** —
136 the counts agree where the topology does, but index *i* need not be the same
137 edge.
138- **`face_offsets` is load-bearing**: `has_ngons()` / `face_start()` /
139 `face_size()` group the corner array into ngons, and `triangulated_indices()`
140 is the fan for rendering. Only `MeshGrid` emits quads so far; the other six
141 primitives still triangulate, and operations that change topology still clear
142 `face_offsets` — correct today only because what they produce IS triangles.
143- `MeshLine` now emits a mesh of points with no triangles (it used to emit a
144 point CLOUD, which baked to nothing).
123145
124146## The erosion filter — one source, three compilations
125147
……@@ -205,6 +227,32 @@ evaluates a node graph inside its own shaders.
205227`VkDevice` bring-up starves, and chunks meshed meanwhile come from a different
206228mesher and STAY. Defer workers, never block.
207229
230### The GLSL debt — 9 nodes are GPU-OFF on purpose (measured 2026-09-05)
231
232The CPU side was re-ported to Blender's arithmetic in #62/#63; the `compile_glsl`
233beside it was not. Rather than let a batch silently evaluate a DIFFERENT function
234from the CPU path, `supports_gpu()` returns false on:
235
236| file:line | node |
237|---|---|
238| `math_nodes.h:29, 58, 212, 256` | Math, VectorMath, MapRange, Mix |
239| `noise_nodes.h:65, 127, 164, 202` | NoiseTexture, VoronoiTexture, WaveTexture, WhiteNoise |
240| `selection_nodes.h:142` | RandomValue |
241
242Math and VectorMath are the sharp ones: the GLSL implements a smaller operation
243set under the OLD numbering, so after renumbering to Blender's it would compute
244the wrong operation with nothing to say so. RandomValue is the reverse shape —
245`supports_gpu()` returned TRUE with no `compile_glsl` override at all, so the GPU
246path never emitted its arithmetic in the first place.
247
248⛔ **Only one instrument can see an emitted-GLSL change.** `gate_dc_vs_lookdev`
249walks the CPU path and is BLIND to it; the in-game oracle SUBMITS density fills
250rather than observing and broke the terrain when it was let run. Use the
251standalone `g++ -O2 -std=c++17 -I src/shared … -lvulkan` gate with its own
252VkDevice — and keep the subject Godot-free in `src/shared/` so the gate compiles
253the SAME TEXT the engine emits. [[project_tile-grid-gpu-gate-2026-09-03]]
254[[feedback_odd-constant-may-be-a-guard]]
255
208256## Zones
209257
210258Input/Output pairs sharing a `zone_id`; the executor finds the pair by BFS from
……@@ -215,9 +263,29 @@ the input node and collects the body in topological order.
215263- **Simulation** — frame-persistent state + `delta_time`; `ProcGeometryNode`
216264 re-evaluates continuously while one is present
217265
218Both zone Input nodes have a `CUSTOM` multi-socket Geometry input that has no
219representable Blender counterpart — 2 of the 6 unresolved sockets, and probably
220permanent.
266Each zone Output node carries an ITEM LIST — Blender models the zone's carried
267values as data, a list of named, typed items each contributing a socket pair.
268`CaptureAttribute` has one, Repeat and Simulation one each, and **Foreach has
269three**: `input_items` sampled per element, `main_items` gathered back as
270fields, `generation_items` produced per element and joined. Two vocabularies for
271one thing and NOT interchangeable — an item reports `data_type` as a CD_PROP
272code (`socket_type_from_cd_prop`, FLOAT_VECTOR 48) while Blender's
273`capture_items.new()` takes a socket-type STRING ('VECTOR').
274
275The zone Input nodes' Geometry socket is now GODOT-ONLY by construction — kept
276past Blender's last socket so nothing can address it — not "unresolved". The old
277claim that it was unrepresentable and permanent was wrong; see [[blender-bridge]].
278
279⛔ **A zone body is an INTERSECTION, not a cone.** `reachable_from_input` walked
280FORWARD from the zone input only, so every node downstream of the zone — Group
281Output included — landed in `body_nodes`, and body nodes are skipped in the main
282loop on the assumption the zone handler runs them. A bridged repeat zone
283therefore baked ZERO vertices while the zone itself was correct on every count
284(3 verts in, 3 through each of 3 iterations, 3 out). It is now forward-reachable
285∩ backward-reachable-from-output, plus the pair itself
286(`graph_executor.cpp:485-509`). Every plausible reading of the symptom pointed
287INTO the zone; the defect was one node outside it, disabled by a set-membership
288test.
221289
222290## Serialization
223291
……@@ -235,6 +303,20 @@ snapshot. So a `.tres` holds deltas, not a full dump.
235303still references it, and the graph then evaluates to **no mesh, silently**.
236304`hyper-tps/graphs/terrain.tres` has been in that state since 2026-03-27.
237305
306⛔ **`connect_sockets` validates the socket index now, and that guard replaced a
307SEGFAULT.** It used to accept anything, and `_read_input_raw` then computed
308`output_values[src_node * max_output_sockets + src_socket]` unbounded: output
309socket 2 of a one-output node lands on a DIFFERENT NODE'S slot, or off the array
310(`proc_node_graph.cpp:188`). It had always been there — what made it crash was
311`IndexNode` becoming a lazy field, so the aliased slot held a promise naming an
312unrelated producer instead of harmless garbage. **A bisect will blame the change
313that made it reachable.**
314
315⚠ **`__extend__` is not a data socket.** Blender's affordance for growing an item
316list carries nothing, and counting it shifted every serialized socket index after
317it — harmless where it sits at the end, wrong on the Foreach OUTPUT node, which
318has one in the MIDDLE between `main_items` and `generation_items`.
319
238320## Blender JSON import
239321
240322`GraphImporter::import_from_json()` consumes what
……@@ -285,4 +367,6 @@ and falls back to the index only when the type there agrees. Run
285367- `docs/nodes.md` — per-node inputs/outputs/defaults
286368- `README.md` — **stale on counts**; architecture and extension guide still good
287369
288Post-mortems: `hyper-games` #60 and its comment; #44/#58 for terrain and GPU.
370Post-mortems: `hyper-games` **#63 and #62** are current (ramp/curve data, zones,
371item lists, multi-input, edges, quads, and the segfault); #60 and its comment for
372the nine earlier disagreements; #44/#58 for terrain and GPU.