Blender add-on: geometry node graph actions, modifier inputs, evaluated snapshot #5

Merged
libby merged 10 commits from libby/blender-gn-recreation into main 2026-11-10 17:54:18 +00:00
Member

Adds Geometry Nodes graph actions to the Blender add-on (brokkr.blender.command_intent.v0), based on main: PR #2 (scene actions) and #4 are merged, so this branch merges main in (e21708e) and the diff is the node-graph cut alone. Owner: surfaces/blender/brokkr_bridge/node_actions.py; fields and limits: surfaces/blender/docs/node-actions.md.

action rule
createNodeGroup geometry group + gin/gout; interface types Geometry/Float/Int/Bool/Vector
addNode / removeNode GeometryNode*/FunctionNode*/ShaderNode* only, no importer/exporter/script/bake/group/zone/viewer/image-texture nodes; properties then inputs; max 500 nodes; gin/gout stay
linkSockets / unlinkSockets by identifier or unique name; invalid links and cycles/self links refused; a refused link restores the link it displaced (incl. muted state)
addModifier / removeModifier / setModifierInput NODES only; getattr(modifier.properties.inputs, id).value (indexing returns a raw IDPropertyGroup on 5.2.3); setObjectCustomProperty refuses a modifier input's Socket_N identifier

Snapshot: mesh objects with modifiers carry evaluated (counts, local vertex bounds and positions, world instance bounds and locations, capped at 256). One depsgraph scan per capture, stopped at 100k items (instancesComplete; unreached objects report instanceCount: null); above 1M vertices counts only; non-finite values set nonFinite. The daemon advertisement now lists the scene-action and node-graph capabilities.

Access rules (for the reviewer): adds write access to node graphs and modifiers on objects of the open Blender file through the same intent queue as existing actions (session token and bind guard from PR #1 apply). No file, network or code-execution path: importer/exporter/script/bake nodes refused; Int values capped at +-4096, floats +-1e9. Residual: a graph can still be expensive to evaluate; removal actions exist to take it out.

Tests: 103 unit tests with a fake bpy (hand mutants killed for each refusal and restore rule); live tests/live/gn_actions.py on headless Blender 5.2.3: 166 checks, 0 failed (ring, boundary_step, seeded scatter rebuilt by actions only and matching native trees; refusals leave no residue; 60-node cycle probe; 2000x2000 instanced grid capture 22 s -> 1.3 s). cargo test -p brokkr-daemon: 20 passed. Three Soul passes (68275e3, a318851, 23a72b2): findings fixed or recorded in the doc.

Not done: zones, item sockets, library groups, group nodes, batches with rollback, expectedRevision; duplicated brokkr_id after a hand copy acts on the first match; instance bounds are a subset when the scan stops. The add-on's Python CAPABILITIES has lacked asset.catalog.read and sync.* since before this branch (main's daemon advertises them).

Re-run at head e21708e after the main merge: tests/live/gn_actions.py on headless Blender 5.2.2 LTS: 166 checks, 0 failed; 104 unit tests pass (10 skipped, need bpy).

Steward pass, 2026-11-10 (head 5bf849d3, merged with main 6f0e700): Soul pass (separate agent) found no bypass of the access rules but found most of them unpinned by tests and three claims off. Fixed: tests now pin the node denylist, idname patterns, and the numeric limits (500, 4096, 1e9, 64, modifiers 8) with literals, the NODES-only modifier checks, rollbacks and the invalid-link removal (a vacuous test fixed); GeometryNodeImageTexture, GeometryNodeInputImage and ShaderNodeTexIES are now refused in code, as the doc said; the doc no longer points at a design file not in this tree (it is PR #3). 119 unit tests pass locally; I reran three hand mutants (MAX_NODES, MAX_INT, Export denial): each fails the suite; Hands reported 38 of 38 killed. Corrections to this body: the committed live result is Blender 5.2.3 LTS (166 checks, 0 failed), not a 5.2.2 rerun; the evaluated-instance timing in the committed JSON is 1.2 s, not 1.3 or 1.4. Not rerun: any live Blender check (Blender is not installed here), the real bpy API. Known and not changed: the daemon advertisement still lists asset.catalog.read and four sync.* capabilities the add-on does not implement (pre-existing); caps bound each value, not graph cost. Brokkr has no CI.

🤖 Generated with Claude Code

Adds Geometry Nodes graph actions to the Blender add-on (`brokkr.blender.command_intent.v0`), based on main: PR #2 (scene actions) and #4 are merged, so this branch merges main in (e21708e) and the diff is the node-graph cut alone. Owner: `surfaces/blender/brokkr_bridge/node_actions.py`; fields and limits: `surfaces/blender/docs/node-actions.md`. | action | rule | |---|---| | `createNodeGroup` | geometry group + `gin`/`gout`; interface types Geometry/Float/Int/Bool/Vector | | `addNode` / `removeNode` | `GeometryNode*`/`FunctionNode*`/`ShaderNode*` only, no importer/exporter/script/bake/group/zone/viewer/image-texture nodes; properties then inputs; max 500 nodes; `gin`/`gout` stay | | `linkSockets` / `unlinkSockets` | by identifier or unique name; invalid links and cycles/self links refused; a refused link restores the link it displaced (incl. muted state) | | `addModifier` / `removeModifier` / `setModifierInput` | NODES only; `getattr(modifier.properties.inputs, id).value` (indexing returns a raw IDPropertyGroup on 5.2.3); `setObjectCustomProperty` refuses a modifier input's `Socket_N` identifier | Snapshot: mesh objects with modifiers carry `evaluated` (counts, local vertex bounds and positions, world instance bounds and locations, capped at 256). One depsgraph scan per capture, stopped at 100k items (`instancesComplete`; unreached objects report `instanceCount: null`); above 1M vertices counts only; non-finite values set `nonFinite`. The daemon advertisement now lists the scene-action and node-graph capabilities. **Access rules (for the reviewer):** adds write access to node graphs and modifiers on objects of the open Blender file through the same intent queue as existing actions (session token and bind guard from PR #1 apply). No file, network or code-execution path: importer/exporter/script/bake nodes refused; Int values capped at +-4096, floats +-1e9. Residual: a graph can still be expensive to evaluate; removal actions exist to take it out. **Tests:** 103 unit tests with a fake `bpy` (hand mutants killed for each refusal and restore rule); live `tests/live/gn_actions.py` on headless Blender 5.2.3: 166 checks, 0 failed (ring, boundary_step, seeded scatter rebuilt by actions only and matching native trees; refusals leave no residue; 60-node cycle probe; 2000x2000 instanced grid capture 22 s -> 1.3 s). `cargo test -p brokkr-daemon`: 20 passed. Three Soul passes (68275e3, a318851, 23a72b2): findings fixed or recorded in the doc. **Not done:** zones, item sockets, library groups, group nodes, batches with rollback, `expectedRevision`; duplicated `brokkr_id` after a hand copy acts on the first match; instance bounds are a subset when the scan stops. The add-on's Python `CAPABILITIES` has lacked `asset.catalog.read` and `sync.*` since before this branch (main's daemon advertises them). Re-run at head e21708e after the main merge: `tests/live/gn_actions.py` on headless Blender 5.2.2 LTS: 166 checks, 0 failed; 104 unit tests pass (10 skipped, need bpy). **Steward pass, 2026-11-10 (head 5bf849d3, merged with main 6f0e700):** Soul pass (separate agent) found no bypass of the access rules but found most of them unpinned by tests and three claims off. Fixed: tests now pin the node denylist, idname patterns, and the numeric limits (500, 4096, 1e9, 64, modifiers 8) with literals, the NODES-only modifier checks, rollbacks and the invalid-link removal (a vacuous test fixed); GeometryNodeImageTexture, GeometryNodeInputImage and ShaderNodeTexIES are now refused in code, as the doc said; the doc no longer points at a design file not in this tree (it is PR #3). 119 unit tests pass locally; I reran three hand mutants (MAX_NODES, MAX_INT, Export denial): each fails the suite; Hands reported 38 of 38 killed. Corrections to this body: the committed live result is Blender 5.2.3 LTS (166 checks, 0 failed), not a 5.2.2 rerun; the evaluated-instance timing in the committed JSON is 1.2 s, not 1.3 or 1.4. Not rerun: any live Blender check (Blender is not installed here), the real bpy API. Known and not changed: the daemon advertisement still lists asset.catalog.read and four sync.* capabilities the add-on does not implement (pre-existing); caps bound each value, not graph cost. Brokkr has no CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Builds a ring array, boundary_step and a seeded scatter natively and through
BrokkrBlenderTarget actions on Blender 5.2.3; records the gaps.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
createNodeGroup, addNode, linkSockets, addModifier, setModifierInput (node_actions.py);
setObjectCustomProperty refuses a name that is a Geometry Nodes modifier input instead of
accepting with no effect; object snapshots carry the evaluated counts, bounds and locations.
Live proof on Blender 5.2.3: ring, boundary_step and seeded scatter rebuilt by actions only
match the native trees (66 checks).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A refused linkSockets puts back the link it displaced; snapshot positions keep local and world
bounds apart, scan instances once per capture, skip positions above 1M vertices and flag
non-finite values; Int values capped at 4096; id/key patterns use fullmatch; addModifier names
the object type it cannot take; setObjectCustomProperty refuses only a modifier input identifier.
Live: 108 checks pass on Blender 5.2.3.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cycles and self links are refused before Blender is asked; the snapshot's instance scan stops at
100k depsgraph items and says instancesComplete=false (2000x2000 instanced grid: 22 s -> 1.4 s);
the daemon advertisement lists the scene-action and node-graph capabilities. Live: 156 checks pass
on Blender 5.2.3.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bpy hands out a fresh wrapper per access, so id() keys made reaches() stop early and accept cycles
on chains of six or more nodes; keyed by as_pointer() with one adjacency map per call. Objects the
stopped instance scan never reached report instanceCount null. removeModifier validates its name.
Live: 158 checks pass on Blender 5.2.3.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A refused link restores the displaced link's is_muted; removeModifier no longer applies the
creation-name pattern to a lookup, so hand-made Unicode modifier names are removable; the
pattern message lists the space it allows. Live: 166 checks pass on Blender 5.2.3.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GeometryNodeImageTexture, GeometryNodeInputImage and ShaderNodeTexIES passed check_idname
though the docs said image-texture nodes are refused. The design doc is not in this tree.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Each denied node family alone, idname shape, 500/64/8/4096/1e9 limits, location, readonly
property, linked/default-less input, foreign modifiers, createNodeGroup rollback, a real
invalid-link removal (the old test hit the cycle check first), and CAPABILITIES for this cut.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libby merged commit 6995eabf51 into main 2026-11-10 17:54:18 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Brokkr!5
No description provided.