Skip to content

Commit a49f342

Browse files
TMHSDigitalclaude
andcommitted
fix(examples): gn-bundle-roundtrip exit-5 falsifier and re-verified version table
Exit 5 had no falsifier. --mismatch-mark renames only Separate's Float item, so count and bbox pass and bundle_mark reads 0.0, exit 5. The README now states the RNA per version as a table, re-verified by probe on 4.5.11, 5.0.1, 5.1.2 and 5.2.1: GeometryNodeCombineBundle is undefined on all of 5.x, not only 5.2; on 4.5 it exists with the experimental flag off and evaluates empty. --force-run on 4.5 is documented as exit 1, not under exit 3. Assertions and exit codes unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent 6f6df42 commit a49f342

2 files changed

Lines changed: 75 additions & 25 deletions

File tree

‎examples/gn-bundle-roundtrip/README.md‎

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,35 @@ Combine Bundle / Separate Bundle packing a cube plus Scale, Offset, and
44
Mark — witnessing [`geometry-nodes-python`](../../skills/geometry-nodes-python/SKILL.md)
55
item-name round-trip, not tree structure.
66

7-
5.x RNA is `NodeCombineBundle` / `NodeSeparateBundle`.
8-
`GeometryNodeCombineBundle` is the **4.5 experimental** id and is undefined
9-
on 5.2. 4.5 LTS keeps the old names behind
10-
`preferences.experimental.use_bundle_and_closure_nodes` (default **off**);
11-
unflagged evaluation is empty. This example skips on 4.5
12-
(`SMOKE_SKIP: Bundles require Blender 5.0+`, exit 77, catalog
13-
`min_version` 5.0). `--force-run` bypasses the skip and creates the 5.x
14-
RNA so 4.5 fails for that reason — not a hidden pass.
7+
## Which RNA, on which Blender
8+
9+
| Blender | Combine / Separate RNA | Legacy `GeometryNodeCombineBundle` | This example |
10+
| --- | --- | --- | --- |
11+
| 4.5 LTS | not defined | defined, but evaluates **empty** unless `preferences.experimental.use_bundle_and_closure_nodes` is on (default **off**) | skips, exit 77 |
12+
| 5.0, 5.1, 5.2 LTS | [`NodeCombineBundle`](https://docs.blender.org/api/current/bpy.types.NodeCombineBundle.html) / [`NodeSeparateBundle`](https://docs.blender.org/api/current/bpy.types.NodeSeparateBundle.html) | **undefined** — `nodes.new` raises `RuntimeError: Node type GeometryNodeCombineBundle undefined` | runs |
13+
14+
If you are porting a 4.5 script to 5.x and `nodes.new("GeometryNodeCombineBundle")`
15+
raises "undefined", the 5.x id has no `GeometryNode` prefix: use
16+
`NodeCombineBundle` / `NodeSeparateBundle`. On 4.5 the reverse holds: `NodeCombineBundle` is
17+
undefined, and the legacy node can be created with the experimental
18+
flag off — it just evaluates to nothing, which is the easy trap.
19+
4.5 API pages: [`GeometryNodeCombineBundle`](https://docs.blender.org/api/4.5/bpy.types.GeometryNodeCombineBundle.html),
20+
[`PreferencesExperimental`](https://docs.blender.org/api/4.5/bpy.types.PreferencesExperimental.html).
21+
22+
Every cell above was re-verified by probe on **4.5.11 LTS, 5.0.1, 5.1.2
23+
and 5.2.1 LTS**. On 4.5.11 the flag exists and reads `False`; a
24+
legacy Combine → Separate carrying a cube evaluates to 0 verts / 0 faces
25+
with it off and 8 / 6 with it on. On 5.0.1, 5.1.2 and 5.2.1 the flag is
26+
gone from `PreferencesExperimental`.
27+
28+
The catalog floor is `min_version` 5.0 and the example prints
29+
`SMOKE_SKIP: Bundles require Blender 5.0+` (exit 77) below it.
30+
`--force-run` bypasses the skip and creates the 5.x RNA, so 4.5 fails
31+
for that reason — `NodeCombineBundle` undefined, caught by the FATAL
32+
wrapper as exit 1 — not a hidden pass. On 5.x `--force-run` changes
33+
nothing and exits 0.
34+
35+
## What it witnesses
1536

1637
Closed form (1 m cube, Scale=2, Offset=`(1.5, 0, 0)`, Mark=`0.314159`):
1738

@@ -21,7 +42,9 @@ Closed form (1 m cube, Scale=2, Offset=`(1.5, 0, 0)`, Mark=`0.314159`):
2142

2243
**Count alone is not enough.** A cube that never entered the bundle is
2344
still 8/6 (`--bypass`). Bbox from the unpacked Scale/Offset is the second
24-
axis; the named attribute from the unpacked Float is the third.
45+
axis; the named attribute from the unpacked Float is the third. Each
46+
axis has its own falsifier, and each falsifier leaves the axes before
47+
it green, so it fails on the axis it names.
2548

2649
No gallery still. The contract is item names + typed round-trip; the
2750
visible mesh is one cube and the attribute is invisible. Failure would
@@ -31,17 +54,19 @@ not read at thumbnail.
3154

3255
- exit 77 — Blender &lt; 5.0 and not `--force-run`
3356
- exit 2 — `GeometryNodeCombineBundle` on 5.x (`--legacy-rna`)
34-
- exit 3 — pairing/names broken (`--mismatch` → 0/0; `--force-run` on 4.5
35-
raises `NodeCombineBundle` undefined, caught as exit 1)
36-
- exit 4 — count matches but unpacked Scale/Offset did not (`--bypass`,
37-
`--pack-scale 1`)
38-
- exit 5 — bbox matches but `bundle_mark` did not travel through the bundle
57+
- exit 3 — item names do not pair, so Separate yields no geometry
58+
(`--mismatch` renames the geometry item → 0/0)
59+
- exit 4 — count matches but the unpacked Scale/Offset did not arrive
60+
(`--bypass`, `--pack-scale 1`)
61+
- exit 5 — count and bbox match but the Float item did not travel
62+
(`--mismatch-mark` renames only the Float item → `bundle_mark` 0.0)
3963

4064
## Run
4165

4266
```bash
4367
blender --background --python gn_bundle_roundtrip.py --
4468
blender --background --python gn_bundle_roundtrip.py -- --force-run
69+
blender --background --python gn_bundle_roundtrip.py -- --mismatch-mark
4570
```
4671

4772
## Exit codes
@@ -52,14 +77,26 @@ against it. `77` is the smoke skip protocol, not a product check.
5277
| Code | Meaning |
5378
| --- | --- |
5479
| 0 | Success |
55-
| 1 | Uncaught exception (FATAL wrapper) |
80+
| 1 | Uncaught exception (FATAL wrapper); `--force-run` on 4.5 lands here |
5681
| 2 | argparse / usage; carrier mesh rewritten; `--legacy-rna` on 5.x |
5782
| 3 | Evaluated vert/face count off closed form (`--mismatch`) |
58-
| 4 | Unpacked Scale/Offset x-extent off (`--bypass`) |
59-
| 5 | `bundle_mark` missing or off closed form |
83+
| 4 | Unpacked Scale/Offset x-extent off (`--bypass`, `--pack-scale 1`) |
84+
| 5 | `bundle_mark` missing or off closed form (`--mismatch-mark`) |
6085
| 77 | `SMOKE_SKIP:` Bundles require Blender 5.0+ |
6186

87+
Measured on 4.5.11 / 5.0.1 / 5.1.2 / 5.2.1:
88+
89+
| Flag | 4.5.11 | 5.0.1 | 5.1.2 | 5.2.1 |
90+
| --- | --- | --- | --- | --- |
91+
| (none) | 77 | 0 | 0 | 0 |
92+
| `--force-run` | 1 | 0 | 0 | 0 |
93+
| `--bypass` | 77 | 4 | 4 | 4 |
94+
| `--legacy-rna` | 77 | 2 | 2 | 2 |
95+
| `--mismatch` | 77 | 3 | 3 | 3 |
96+
| `--mismatch-mark` | 77 | 5 | 5 | 5 |
97+
| `--pack-scale 1` | 77 | 4 | 4 | 4 |
98+
6299
The `blender-smoke` workflow runs the check on Blender 5.2 LTS (5.1 on the
63100
weekly cron, the `needs-5.1` PR label, or manual dispatch) and skips on 4.5
64-
LTS. Smoke does not pass `--bypass`, `--legacy-rna`, `--mismatch`, or
65-
`--force-run`.
101+
LTS. Smoke does not pass `--bypass`, `--legacy-rna`, `--mismatch`,
102+
`--mismatch-mark`, or `--force-run`.

‎examples/gn-bundle-roundtrip/gn_bundle_roundtrip.py‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Witnesses Combine / Separate Bundle from ``skills/geometry-nodes-python``.
44
The load-bearing RNA on 5.x is ``NodeCombineBundle`` / ``NodeSeparateBundle``,
55
not ``GeometryNodeCombineBundle`` (that id is 4.5 experimental and
6-
**undefined** on 5.2). Tree-structure checks are vacuous: the nodes can
6+
**undefined** on 5.x). Tree-structure checks are vacuous: the nodes can
77
exist and be linked while Separate looks up the wrong item names and
88
evaluates empty.
99
@@ -23,6 +23,7 @@
2323
bypasses the skip and uses the 5.x RNA so 4.5 fails for that reason.
2424
2525
blender --background --python gn_bundle_roundtrip.py --
26+
blender --background --python gn_bundle_roundtrip.py -- --mismatch-mark
2627
"""
2728
import argparse
2829
import sys
@@ -61,7 +62,7 @@ def eval_mesh(obj):
6162
return coords, faces, marks
6263

6364

64-
def build_tree(pair=True, match_names=True, pack_scale=PACK_SCALE):
65+
def build_tree(pair=True, match_names=True, pack_scale=PACK_SCALE, match_mark=True):
6566
tree = bpy.data.node_groups.new("BundleRoundTrip", "GeometryNodeTree")
6667
tree.interface.new_socket(
6768
name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry",
@@ -84,7 +85,10 @@ def build_tree(pair=True, match_names=True, pack_scale=PACK_SCALE):
8485
sep.bundle_items.new("GEOMETRY", sep_mesh)
8586
sep.bundle_items.new("FLOAT", "Scale")
8687
sep.bundle_items.new("VECTOR", "Offset")
87-
sep.bundle_items.new("FLOAT", "Mark")
88+
# --mismatch-mark renames only the Float item: the mesh, Scale and Offset
89+
# still round-trip, so count and bbox pass and only the mark is lost.
90+
sep_mark = "Mark" if match_mark else "Marker"
91+
sep.bundle_items.new("FLOAT", sep_mark)
8892

8993
tree.links.new(cube.outputs["Mesh"], comb.inputs["Mesh"])
9094
comb.inputs["Scale"].default_value = pack_scale
@@ -106,19 +110,22 @@ def build_tree(pair=True, match_names=True, pack_scale=PACK_SCALE):
106110
tree.links.new(xyz.outputs["Vector"], xf.inputs["Scale"])
107111
tree.links.new(sep.outputs["Offset"], xf.inputs["Translation"])
108112
tree.links.new(xf.outputs["Geometry"], store.inputs["Geometry"])
109-
tree.links.new(sep.outputs["Mark"], store.inputs["Value"])
113+
tree.links.new(sep.outputs[sep_mark], store.inputs["Value"])
110114
tree.links.new(store.outputs["Geometry"], go.inputs["Geometry"])
111115
return tree
112116

113117

114-
def build(pair, match_names, pack_scale):
118+
def build(pair, match_names, pack_scale, match_mark=True):
115119
bpy.ops.wm.read_factory_settings(use_empty=True)
116120
me = bpy.data.meshes.new("Carrier")
117121
me.vertices.add(1)
118122
ob = bpy.data.objects.new("Carrier", me)
119123
bpy.context.collection.objects.link(ob)
120124
mod = ob.modifiers.new("GN", "NODES")
121-
mod.node_group = build_tree(pair=pair, match_names=match_names, pack_scale=pack_scale)
125+
mod.node_group = build_tree(
126+
pair=pair, match_names=match_names, pack_scale=pack_scale,
127+
match_mark=match_mark,
128+
)
122129
bpy.context.view_layer.update()
123130
return ob
124131

@@ -194,6 +201,11 @@ def main():
194201
action="store_true",
195202
help="falsification: Separate item name Geom vs Combine Mesh",
196203
)
204+
p.add_argument(
205+
"--mismatch-mark",
206+
action="store_true",
207+
help="falsification: Separate Float item Marker vs Combine Mark",
208+
)
197209
p.add_argument("--pack-scale", type=float, default=PACK_SCALE)
198210
p.add_argument(
199211
"--legacy-rna",
@@ -224,6 +236,7 @@ def main():
224236
pair=not args.bypass,
225237
match_names=not args.mismatch,
226238
pack_scale=args.pack_scale,
239+
match_mark=not args.mismatch_mark,
227240
)
228241
code = check(ob)
229242
if code:

0 commit comments

Comments
 (0)