BLENDER_WORKBENCH and BLENDER_EEVEE aborted the whole Blender process inside
bpy.ops.render.render with no receipt. The probe is cached, Linux only, and a
module-level function so tests replace it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cultmesh_py (CultLib GameCult/CultLib#33) refuses peer puts and deletes unless a
write authority grants them. The add-on's clients put command intents, and the
session token guard already authenticates them, so the target passes
CultMeshGrantAllWrites() when cultmesh_py has it. Older cultmesh_py already
accepts every write and is left alone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- check_relative: spaces before the first dot are dropped (CON .txt), superscript COM/LPT digits are device names.
- gltf_references refuses a reference to a missing file; drops the broad ValueError catch and redundant relative_to so the specific refusal (a link) reaches the receipt.
- _render_still makes folders only after every Blender-side refusal (unknown engine used to leave them behind).
- Tests for each.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- resolve_inside maps OSError from resolving a component (WinError 448 on a mklink /J junction) to a link refusal.
- Direct check_relative test for '..' and NUL; OSError mapping test.
- headless_smoke.py makes real junctions on Windows (outside and inside the root) and an existing-output case.
- install.md documents the path rules and the residual TOCTOU.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WIP for review fixes, tests pass (61); mutation confirmation and Starfire re-run pending.
- importGltf parses .gltf JSON and .glb's JSON chunk, checks every buffers/images uri.
- Names are relative plain paths: no drive, UNC, extended, ':' (ADS), '..', device names.
- No symlink/junction component under the root; output must not already exist.
- Path and file stamps re-checked right before use; residual TOCTOU documented in code.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found by running the actions on Blender 5.2.3 headless: the render engine enum is
dynamic, bl_rna lists only BLENDER_EEVEE, so CYCLES and WORKBENCH were refused.
The fake in the tests now behaves like the real enum. surfaces/blender/tests/live/
headless_smoke.py runs every scene action against real bpy.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Panel offers only the Copy Session Token button; the token is not drawn.
- Fake-bpy tests: allow_non_loopback carries an update callback that stops a running
non-loopback server; copy operator writes the clipboard; the panel never draws the token.
- Real-server test: a DELETE with shardId and a valid token leaves no token in the shard log.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- The guarded server removes sessionToken from put/delete messages before the store,
which copies envelope fields into the shard log it serves.
- Copy Session Token operator.
- Panel shows cultmesh_py's loaded __file__, not the preference path.
- Unticking Allow Non-Loopback (and any refused start) stops a running non-loopback server.
- stop_server revokes, purges and clears state even if the socket stop raises.
- Tests: shard-log token leak on the real server, node half of the start purge, purge
persisted across reopening the .ccmp, allow=True through start_server, finally-path.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Paths for importGltf and renderStill are confined to the Import Directory and
Render Output Directory preferences (empty disables the action; .. , absolute
paths and escaping symlinks are refused). Every field is validated before bpy is
touched. renderStill restores render settings afterwards. Tests use a fake bpy;
Blender was not run.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Optional per-session token (preference, default off): random secrets token at
Start Server, shown in the panel, required in the sessionToken envelope field on
every document put and delete, revoked on Stop, never persisted.
- Always on: queued command intents (node records and debug command JSONs) are
purged on server start and stop; the panel shows the bind address and the
cultlib_py_src path; a non-loopback Serve Host is refused unless the
Allow Non-Loopback Bind preference is ticked, with a panel warning while running.
- Tests without Blender, plus real cultmesh_py server tests when CULTLIB_PACKAGES is set.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Per thing2:ruling:eve-dashboards-quarantined. Removes eveSurfaces from the provider advertisement and its schema, the two surface URIs, the eve.gui/eve.tui publish capabilities, and Eve wording in docs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Directory.Build.props names CultLibRoot (CULTLIB_ROOT, else the sibling checkout) and pins CultLibRevision to cultlib-unity-v2.0.0 (42dce361). Directory.Build.targets fails the build unless that checkout is at the pin and clean, as Aetheria's guard does. Project references use CultLibRoot.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Eyes pass 2026-10-10: tools, limits and security posture of the official
Blender Lab MCP, the community BlenderMCP and Blender Agent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The editor service is the one command owner, the sink is off by default,
command ids are single-use, and stale intents expire on enable in one
conditional cache commit. Soul pass 4 verdict: merge. Recorded follow-up:
TryCommitEnableAsync does not retry when a concurrent PutAsync leaves
staged writes; unreachable on Unity's main thread and fails safe.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The enable commit is conditional (ExpectUnchanged) and lives in the new
Runtime BrokkrCommandStore, with the pull-recompute-retry loop in
BrokkrCommandDrain.EnableAsync, so the tests exercise the shipped code. An
intent landing between the pull and the commit is expired, not run; eight
refusals in a row fail the enable loudly with the sink off. The probe is now
a thin fault-injecting wrapper over the real store, not a copy of it.
- Every editor write to the command lane is one cache commit; durable shard
logs are off (no server, no reader).
- No receipt is pruned before ten minutes, whatever the count, and the CLI
refuses a wait over five minutes. Fixed the comments that claimed otherwise.
- Pending and Prunable count a document only under the key its own id names.
- README and snapshot comment: the token stops stale EditorPrefs, it does not
authenticate writers; a restored or sync-conflict copy of the editor's own
store can rerun answered intents.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Database.PutAsync appends a mutation-log entry per record, so expiring 2000
intents took 17 s even with one flush. The drain's two bulk writes are now
atomic CultCache commits, so the enable cannot half-apply and the cost is per
commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Soul pass 2 findings S1, S2, S3, S4.
- Enabling the sink is the drain's EnableAsync: every intent already in the
store gets an "expired" receipt and the enable marker is written, all in one
flush. No decision compares StoredAt with a clock any more, so a fast
writer clock and the Rust daemon's secs.nanosZ stamps stop mattering.
- The operator's EditorPrefs hold a token, and the sink runs only while the
store carries the marker with that token. A re-clone or a copied .brokkr has
no such marker, so a stale "enabled" authorizes nothing and the editor drops
it. The epoch and agentCommandsEnabledAt (host snapshot key 19) are gone.
- Selection is one pass over the store per tick (Pending), not a copy and sort
per intent.
- Receipts are capped at the newest 1000, pruned 128 pairs per tick with the
intent deleted before its receipt.
- A marker that could not be written is withdrawn, so the intent reads as
never started and is retried, not "interrupted".
- The drain writes through IBrokkrCommandStore; puts stage and one flush makes
them durable.
- The CLI timeout text no longer says the intent "stays written" without the
expiry caveat; the check-then-write window on --command-id is documented.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A store that fails to open is not always unreadable (a held lock does it too),
so the message says what happened. The catch-all's test now corrupts the store
after the CLI opened it, which the open's own handling cannot see.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The sink-off gate lives in the Unity service, not the drain, so the harness test
proved nothing about the machine. The new test reaches the CLI's last-resort
exit code with a failure that happens after the store opened.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Any exception now exits 2 with a message. An empty or legacy store fails with
a message that names the path instead of aborting with 134.
- A --command-id that already has a receipt is refused with exit 2, so a stale
receipt is never reported as the answer to a new intent.
- The wait treats the editor's "attempted" marker as not yet a verdict.
- The action theory passes --output so captureEditorView clears admission now
that the harness runs the real policy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The window republished a snapshot it had captured earlier, which could carry a
stale agentCommandsEnabled. Publish Mirror and Auto Publish now ask the service
to capture and publish a fresh one; the window keeps the returned snapshot for
display only.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BrokkrCommandDrain owns every rule between a pending intent and its receipt.
The service and the scenario harness now run the same drain instead of two
copies of the loop.
- An "attempted" receipt is written and flushed before Execute. A crash or a
failing final receipt write can no longer re-run an intent; the next drain
rewrites a leftover marker as "interrupted" and the operator decides.
- The host snapshot carries the sink's enable epoch. Intents stored before the
latest enable get an "expired" receipt and never run (operator ruling
2026-09-30).
- One drain handles at most 16 intents, expired and denied ones included.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
editor.assets.refresh, editor.lifecycle.write and editor.view.capture join
the Unity surface, in the provider contract and the advertisement test. The
donor's prefab mirror rows are not taken; that pipeline is parked.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>