Skip to content

Commit 3c5490b

Browse files
TMHSDigitalclaude
andcommitted
fix(examples): stop two falsifiers passing for the wrong reason
extension-package-lifecycle returned 4 both when validate rejected the missing-wheel package and when build accepted it, so --ship-wheel (expect 4) would stay green even if a future validate started checking wheel paths and the example's lesson inverted. Validate-rejects now has its own exit, 9. Verified on 5.2.1: the default run exits 0 and --ship-wheel exits 4. temp-override-join's --clear-active-on-deselect wrote active = None itself and then read it back, so its exit 13 proved nothing about Blender. No deselection Blender offers clears the active object (that is the contract), so no operation-level falsifier exists, and the default run is the witness. The flag stays as a documented self-check of the exit-13 report and leaves the catalog. --no-override (exit 3) remains the row's falsifier. Verified on 5.2.1: default 0, --no-override 3, self-check 13. Closes #489 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent f8dd085 commit 3c5490b

5 files changed

Lines changed: 24 additions & 15 deletions

File tree

‎examples/extension-package-lifecycle/README.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ Scaffolding matches [`eval-mesh-datablock-name`](../eval-mesh-datablock-name/)
3939
- exit 4 — `build` accepted the package whose manifest names a wheel it does
4040
not ship, so nothing between `validate` and a release would catch it
4141
(`--ship-wheel` lands here: it creates the named wheel, so `build` exits 0
42-
and writes a zip, proving the rejection comes from the missing file); also
43-
exit 4 if `validate` starts rejecting the package, because the trap this
44-
example names would then be gone
42+
and writes a zip, proving the rejection comes from the missing file)
4543
- exit 5 — `server-generate` wrote no listing, or the listing does not name the package
4644
- exit 6 — install, import, upgrade or remove failed, or `__package__` is not
4745
`bl_ext.user_default.example_addon`
4846
- exit 7 — user data lives inside the install tree, did not survive the
4947
upgrade, or survived removal (`--data-next-to-file` lands here: it stores
5048
data beside `__file__`)
5149
- exit 8 — `online_access` is not `False` by default and `True` under `--online-mode`
50+
- exit 9 — `validate` rejected the missing-wheel package, so the trap this
51+
example names is gone (its own code, so `--ship-wheel` can only land on 4)
5252

5353
## Re-verified
5454

@@ -91,11 +91,12 @@ than most examples.
9191
| 1 | Uncaught exception (FATAL wrapper) |
9292
| 2 | argparse / usage |
9393
| 3 | Template does not validate or build, or the zip lacks its manifest |
94-
| 4 | `build` accepted the missing-wheel package, or `validate` rejected it (`--ship-wheel` lands here) |
94+
| 4 | `build` accepted the missing-wheel package (`--ship-wheel` lands here) |
9595
| 5 | `server-generate` listing missing or wrong |
9696
| 6 | Install, import, upgrade or remove failed, or `__package__` wrong |
9797
| 7 | User data inside the install tree, lost on upgrade, or kept after removal (`--data-next-to-file` lands here) |
9898
| 8 | `online_access` default or `--online-mode` value wrong |
99+
| 9 | `validate` rejected the missing-wheel package: the validate-is-not-a-gate trap is gone |
99100

100101
The `blender-smoke` workflow runs the check on Blender 5.2 LTS and 4.5 LTS
101102
(5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch).

‎examples/extension-package-lifecycle/extension_package_lifecycle.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ def check_wheel_trap(work, ship_wheel):
113113
print(f"{'shipped' if ship_wheel else 'missing'} wheel: validate exit {v_code}, "
114114
f"build exit {b_code}, output {shipped}")
115115
if v_code != 0:
116+
# Its own code (#489): sharing 4 with the build check let --ship-wheel
117+
# pass on either branch.
116118
return fail("validate rejects the package; the validate-is-not-a-gate trap this "
117-
"example names is gone", 4)
119+
"example names is gone", 9)
118120
if b_code == 0 or shipped:
119121
return fail(f"build accepted the package (exit {b_code}, output {shipped}); "
120122
"only build can reject a wheel the manifest names but the source lacks", 4)

‎examples/temp-override-join/README.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ still `context.active_object` while `selected_objects` is empty and
2929
`target.select_get()` is `False`. Active and selected are independent, so an
3030
`if obj is None` guard passes on a selection that is gone (see the
3131
[`operators`](../../skills/operators/SKILL.md) skill, Defensive context handling). The scene
32-
is then reset to no active object before the join. `--clear-active-on-deselect` models the
33-
wrong belief that deselecting clears the active object, and exits 13.
32+
is then reset to no active object before the join. `--clear-active-on-deselect` is a
33+
self-check, not a falsifier: the script clears the active object itself, then shows exit 13
34+
reports it. No Blender deselection clears the active object (that is the contract), so the
35+
default run is the witness: if a Blender release changed that, it would exit 13 (#489).
3436

3537
**The render is the joined object.** Everything in the still is one mesh object. It shows
3638
five materials because the slots merged and the per-face indices were remapped. If they had
@@ -46,7 +48,7 @@ blender --background --python temp_override_join.py --
4648
# Falsifier: join without temp_override. Must exit non-zero.
4749
blender --background --python temp_override_join.py -- --no-override
4850

49-
# Falsifier: pretend deselect-all clears the active object. Must exit 13.
51+
# Self-check (not a falsifier): clear the active object by hand; exit 13 reports it.
5052
blender --background --python temp_override_join.py -- --clear-active-on-deselect
5153

5254
# Also render a still (EEVEE on a GPU host; use --engine cycles on GPU-less hosts):
@@ -78,5 +80,5 @@ against it.
7880

7981
The `blender-smoke` workflow runs the check on Blender 5.2 LTS and 4.5 LTS
8082
(5.1 on the weekly cron, the `needs-5.1` PR label, or manual dispatch).
81-
Smoke does not pass `--output`. Its catalog falsifiers are `--no-override` (expects exit 3) and `--clear-active-on-deselect` (exit 13).
83+
Smoke does not pass `--output`. Its catalog falsifier is `--no-override` (expects exit 3). `--clear-active-on-deselect` is not in the catalog: it reaches exit 13 only by writing the value the check reads, so it would pass whatever Blender did (#489).
8284

‎examples/temp-override-join/temp_override_join.py‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,18 @@
3030
leaves ``context.active_object`` set to the target while
3131
``selected_objects`` is empty, so an ``if obj is None`` guard passes on a
3232
selection that is gone. The scene state is then reset to no active object
33-
and nothing selected, as before. ``--clear-active-on-deselect`` models the
34-
wrong belief (deselect clears the active object) and exits 13.
33+
and nothing selected, as before. ``--clear-active-on-deselect`` is a
34+
self-check, not a falsifier: it clears the active object itself and shows
35+
that exit 13 reports it. No deselection Blender offers clears the active
36+
object (that is the contract), so the happy path is the witness: if Blender
37+
ever changed, the default run would exit 13 (#489).
3538
3639
By default it runs only the correctness check (no render) — the CI smoke
3740
check. Pass --output to also render a still:
3841
3942
blender --background --python temp_override_join.py -- # check only
4043
blender --background --python temp_override_join.py -- --no-override # must fail
41-
blender --background --python temp_override_join.py -- --clear-active-on-deselect # 13
44+
blender --background --python temp_override_join.py -- --clear-active-on-deselect # 13, self-check
4245
blender --background --python temp_override_join.py -- --output j.png # + render
4346
"""
4447
import argparse
@@ -380,7 +383,7 @@ def check_active_survives_deselect(objs, clear_active=False):
380383
ob.select_set(True)
381384
bpy.ops.object.select_all(action='DESELECT')
382385
if clear_active:
383-
view_layer.objects.active = None # the wrong mental model, made true
386+
view_layer.objects.active = None # self-check of the exit-13 report, not Blender
384387
active = bpy.context.active_object
385388
if active is None:
386389
active_name = None # what the wrong mental model predicts
@@ -566,7 +569,8 @@ def main():
566569
p.add_argument("--no-override", action="store_true",
567570
help="join without temp_override (must fail)")
568571
p.add_argument("--clear-active-on-deselect", action="store_true",
569-
help="clear the active object after deselect-all (must fail, exit 13)")
572+
help="self-check: clear the active object after deselect-all "
573+
"and show exit 13 reports it (not a Blender falsifier)")
570574
args = p.parse_args(argv)
571575

572576
bpy.ops.wm.read_factory_settings(use_empty=True)

‎tests/smoke/catalog.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{"name": "driver-wave", "script": "examples/driver-wave/driver_wave.py", "falsifiers": [{"args": ["--flat-expr"], "expect_exit": 3}, {"args": ["--simple-expr"], "expect_exit": 5}, {"args": ["--swap-handlers"], "expect_exit": 7}]},
1414
{"name": "bmesh-gear", "script": "examples/bmesh-gear/bmesh_gear.py", "falsifiers": [{"args": ["--no-extrude"], "expect_exit": 3}]},
1515
{"name": "shader-node-group", "script": "examples/shader-node-group/shader_node_group.py", "falsifiers": [{"args": ["--same-tint"], "expect_exit": 8}]},
16-
{"name": "temp-override-join", "script": "examples/temp-override-join/temp_override_join.py", "falsifiers": [{"args": ["--no-override"], "expect_exit": 3}, {"args": ["--clear-active-on-deselect"], "expect_exit": 13}]},
16+
{"name": "temp-override-join", "script": "examples/temp-override-join/temp_override_join.py", "falsifiers": [{"args": ["--no-override"], "expect_exit": 3}]},
1717
{"name": "gn-instance-grid", "script": "examples/gn-instance-grid/gn_instance_grid.py", "falsifiers": [{"args": ["--one-cell"], "expect_exit": 4}]},
1818
{"name": "gn-modifier-inputs", "script": "examples/gn-modifier-inputs/gn_modifier_inputs.py", "falsifiers": [{"args": ["--same-height"], "expect_exit": 8}, {"args": ["--api", "dict"], "expect_exit": 5, "min_version": "5.2"}]},
1919
{"name": "shape-key-blend", "script": "examples/shape-key-blend/shape_key_blend.py", "falsifiers": [{"args": ["--zero-blend"], "expect_exit": 5}]},

0 commit comments

Comments
 (0)