Summary
The non-configurable code-edit hard-block (dispatch_gate step [0], error CODE_EDIT_BLOCKED) is applied to iris_execute, iris_execute_method and iris_query, but not to iris_ws_exec. A caller who cannot edit compiled code through iris_execute can do the same edit through a WebSocket terminal session, which routes around the guard entirely.
The write gate (085) does cover iris_ws_exec (wr classification), so this is not a write-gate gap — it is specifically the code-edit hard-block, and the spec-087 literal-Kill ^ destructive check, that do not extend to the WebSocket path.
Environment
iris-agentic-dev 1.3.0 (measured live) and 1.4.1 (source-verified) — the bug is present on the latest release.
- IRIS 2025.3 Community, MCP over stdio.
Evidence — measured live on 1.3.0, write_tools_enabled = true (the normal operating state for any compile/test workflow)
Same code, two tools, opposite outcomes:
iris_execute { code: 'do $System.OBJ.Compile("App.Data.Person","ck")' }
-> { "error_code": "CODE_EDIT_BLOCKED", "matched": "$SYSTEM.OBJ.COMPILE" }
iris_ws_open {} -> session opened
iris_ws_exec { session, code: 'do $System.OBJ.Compile("App.Data.Person","ck")' }
-> EXECUTED: "Compilation started ... Compiling class App.Data.Person ... finished successfully"
The destructive literal-Kill ^ check (spec 087) is also skipped, with destructive_tools_enabled = false:
iris_ws_exec { session, code: 'kill ^zzProbeDoesNotExist write "kill-ran"' }
-> EXECUTED: "kill-ran"
Control confirming this is not a write-gate hole (write_tools_enabled = false):
iris_ws_exec { session, code: 'write 1' } -> { "error_code": "WRITE_TOOLS_DISABLED" }
Source
crates/iris-agentic-dev-core/src/policy/gate.rs, dispatch_gate() step [0], on both v1.3.0 and v1.4.1, only branches on iris_execute, iris_execute_method (added in 1.4.x) and iris_query. iris_ws_exec never reaches check_objectscript_code_edit. Meanwhile tools/write_gate.rs classifies iris_ws_exec as wr and even comments "goes through iris_ws_exec, which is where the gate belongs" — so the write tier was deliberately routed through it, but the code-edit tier was not.
Why it matters
The code-edit hard-block is documented as a non-configurable protection: "Blocks editing class/routine code through arbitrary-execution tools, which otherwise sidestep the system blocklist." Its value is that an agent with write access — which every compile/test session needs — still cannot rewrite %Dictionary, run $system.OBJ, or touch ^rOBJ through ad-hoc execution. iris_ws_exec reopens exactly that path in the normal write_tools_enabled = true state, so the guarantee holds for iris_execute and silently does not for the WebSocket terminal. An agent reaching for a terminal session (a natural fallback when iris_execute refuses) gets the unguarded path.
Existing tracking
Spec 087-execute-gate-bypass explicitly lists iris_ws_exec under Out of scope — "separate analysis needed; same class of problem" — but no issue tracks it, and 1.4.x extended [0] to iris_execute_method without picking it up. This issue is that separate analysis.
Suggested fix
Route iris_ws_exec's code through the same check_objectscript_code_edit before it reaches the session pool — either by adding an iris_ws_exec branch to dispatch_gate step [0], or by calling the guard in the iris_ws_exec handler. The PHI and system-global checks that apply to iris_execute global operations should follow the same reasoning.
Reported from the iris-ai-bootstrap kit, which in the meantime removes iris_ws_open / iris_ws_exec / iris_ws_close from its own tool surface via IRIS_DISABLED_TOOLS.
Summary
The non-configurable code-edit hard-block (
dispatch_gatestep[0], errorCODE_EDIT_BLOCKED) is applied toiris_execute,iris_execute_methodandiris_query, but not toiris_ws_exec. A caller who cannot edit compiled code throughiris_executecan do the same edit through a WebSocket terminal session, which routes around the guard entirely.The write gate (085) does cover
iris_ws_exec(wrclassification), so this is not a write-gate gap — it is specifically the code-edit hard-block, and the spec-087 literal-Kill ^destructive check, that do not extend to the WebSocket path.Environment
iris-agentic-dev1.3.0 (measured live) and 1.4.1 (source-verified) — the bug is present on the latest release.Evidence — measured live on 1.3.0,
write_tools_enabled = true(the normal operating state for any compile/test workflow)Same code, two tools, opposite outcomes:
The destructive literal-
Kill ^check (spec 087) is also skipped, withdestructive_tools_enabled = false:Control confirming this is not a write-gate hole (
write_tools_enabled = false):Source
crates/iris-agentic-dev-core/src/policy/gate.rs,dispatch_gate()step[0], on bothv1.3.0andv1.4.1, only branches oniris_execute,iris_execute_method(added in 1.4.x) andiris_query.iris_ws_execnever reachescheck_objectscript_code_edit. Meanwhiletools/write_gate.rsclassifiesiris_ws_execaswrand even comments "goes through iris_ws_exec, which is where the gate belongs" — so the write tier was deliberately routed through it, but the code-edit tier was not.Why it matters
The code-edit hard-block is documented as a non-configurable protection: "Blocks editing class/routine code through arbitrary-execution tools, which otherwise sidestep the system blocklist." Its value is that an agent with write access — which every compile/test session needs — still cannot rewrite
%Dictionary, run$system.OBJ, or touch^rOBJthrough ad-hoc execution.iris_ws_execreopens exactly that path in the normalwrite_tools_enabled = truestate, so the guarantee holds foriris_executeand silently does not for the WebSocket terminal. An agent reaching for a terminal session (a natural fallback wheniris_executerefuses) gets the unguarded path.Existing tracking
Spec
087-execute-gate-bypassexplicitly listsiris_ws_execunder Out of scope — "separate analysis needed; same class of problem" — but no issue tracks it, and 1.4.x extended[0]toiris_execute_methodwithout picking it up. This issue is that separate analysis.Suggested fix
Route
iris_ws_exec'scodethrough the samecheck_objectscript_code_editbefore it reaches the session pool — either by adding aniris_ws_execbranch todispatch_gatestep[0], or by calling the guard in theiris_ws_exechandler. The PHI and system-global checks that apply toiris_executeglobal operations should follow the same reasoning.Reported from the
iris-ai-bootstrapkit, which in the meantime removesiris_ws_open/iris_ws_exec/iris_ws_closefrom its own tool surface viaIRIS_DISABLED_TOOLS.