Skip to content

fix(examples): make the examples follow the rules they teach, and lint it - #431

Merged
TMHSDigital merged 1 commit into
mainfrom
fix/example-rule-lint
Oct 5, 2026
Merged

TMHSDigital merged 1 commit into
mainfrom
fix/example-rule-lint

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Closes #400.

Problem

Agents copy these scripts (bmesh-gear is the documented anatomy), but nothing checked them against the repo's own rules, and they broke them.

Change

  • Scripted AST rewrite: 127 loops in 100 files.
    • for p in X.polygons: p.use_smooth = E becomes X.polygons.foreach_set("use_smooth", …). That is a constant fill when E doesn't use p, and a comprehension otherwise.
    • for v in X.vertices: v.co.z += D becomes foreach_get → shift co[2::3] → foreach_set.
    • Inline comments are carried over. No collision with existing _co names in the same function (checked).
  • 7 by hand:
    • constant material_index fills: boolean-exact-volume, depsgraph-export, gn-sdf-remesh, soccer seams;
    • uniform co scale and offset: prop-origin-transform ×2, collision-hull --shrink-hull;
    • moka-pot --lean-pot.
  • 8 marked # foreach-exempt: <why>. These have genuinely per-element logic: car-mirror ring bands, collision-hull bonnet height, the lightmap post arc fit, mesh-hygiene n-gon marking, the soccer pentagon test, triangulate-tangents build-order bands, and the bowling-ball surface test.
  • 7 active_object reads (compositor-glare, gn-sdf-remesh ×3, grease-pencil-rosette ×2, turntable) get if X is None: raise RuntimeError(...).
  • New tests/check_example_rules.py in Validate. It flags:
    • an unmarked per-element write in a loop over .polygons/.vertices. Those names exist only on Mesh, since BMesh uses faces/verts, so bmesh code never triggers it;
    • an active_object assignment not directly followed by if X is None.
  • docs/new-example-prompt.md documents the lint and the marker.
  • Out of scope: the bmesh-lifetime half of showcase: hay-bale leaks a bmesh via 'finally: pass'; always-free-bmesh rule disagrees with builder/ownership-transfer code #401 (builder classes that own a BMesh). It stays tracked there.

Evidence

Equivalence, live run. Binary reports 5.2.1 LTS. Each pair runs main's script and this branch's:

Script / args exit (old/new) stdout identical
bmesh-gear 0/0 yes
anvil · anvil --lift-z 0/0 · 16/16 yes · yes
moka-pot --lean-pot · --lift-z 19/19 · 16/16 yes · yes
prop-origin-transform 0/0 yes
collision-hull-proxy · --shrink-hull 0/0 · 3/3 yes · yes
soccer-ball-goldberg · --invert-bind 0/0 · 13/13 yes · yes

"Identical" excludes timing and temp-path lines. CI smoke runs every happy path and catalog falsifier on 5.2 and 4.5.

Checker: passes on 140 scripts. On main it reports 15 violations after the scripted pass, which are the hand-fixed and marked sites above.

check_helper_drift, check_exit_code_readme, check_render_gates, check_engine_id and check_witnesses pass. The gallery is unchanged: it links sources rather than inlining them.

🤖 Generated with Claude Code

…t it

Agents copy these scripts (bmesh-gear is the documented anatomy), but
nothing checked them against the repo's own rules, and they broke them:
53 per-face `use_smooth` loops (three in bmesh-gear), 74 per-vertex
`v.co.z += ...` loops, more per-element material/co writes, and seven
`active_object` reads with no None guard.

- 127 single-statement loops became foreach_set / foreach_get by a
  scripted AST rewrite (inline comments kept); seven more hand-converted
  (constant material indices, uniform co scale/offset, the moka-pot lean).
- Eight loops with genuinely per-element logic (ring/station material
  bands, n-gon marking, ball-surface tests) carry a
  `# foreach-exempt: <why>` marker.
- Seven `X = bpy.context.active_object` reads get `if X is None: raise`.
- tests/check_example_rules.py (Validate) rejects an unmarked
  per-element write in a loop over .polygons/.vertices (Mesh-only names,
  so bmesh code is never hit) and an unguarded active_object read.

Old and new versions of six scripts, run on 5.2.1 across ten paths
including the touched falsifiers, print identical output with identical
exit codes.

Closes #400

Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added examples Runnable smoke-gated examples under examples/ showcase Budget-conformance props under showcase/ documentation Improvements or additions to documentation ci labels Oct 5, 2026
@TMHSDigital

Copy link
Copy Markdown
Owner Author

CI evidence before merge: all checks pass ( 13 pass ). Blender Smoke on PR head: Blender 5.2.2 LTS / Blender 4.5.14 LTS. Summaries (happy path; falsifiers) per leg: 141 passed, 3 skipped, 0 failed;136 passed, 7 skipped, 0 failed;143 passed, 1 skipped, 0 failed;143 passed, 0 skipped, 0 failed;

@TMHSDigital
TMHSDigital merged commit 7ca0fdc into main Oct 5, 2026
13 checks passed
@TMHSDigital
TMHSDigital deleted the fix/example-rule-lint branch October 5, 2026 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci documentation Improvements or additions to documentation examples Runnable smoke-gated examples under examples/ showcase Budget-conformance props under showcase/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

testing: the repo's own rules are never linted against its 140 example/showcase scripts, and those scripts break them

1 participant