mirror of
https://github.com/mikeyobrien/ralph-orchestrator.git
synced 2026-04-24 22:55:57 +03:00
[PR #198] feat(core): add disallowed_tools, stale loop detection, and file-modification audit #193
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/ralph-orchestrator#193
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/mikeyobrien/ralph-orchestrator/pull/198
Author: @arjhun-personal
Created: 2/25/2026
Status: 🔄 Open
Base:
main← Head:feat/loop-cycling-phase2📝 Commits (10+)
159821dfeat(core): add hat scope enforcement, event chain validation, and human timeout routing63111d9docs: add upstream PR draft for hat scope enforcement479e6cbfeat(core): make hat enforcement opt-in via config flagsdd46589style: fix rustfmt formatting in hat enforcement code31c55efspec: add context window utilization tracking designadce9bcfix(core): record default_publishes topics in seen_topics for chain validation4da8468docs: add upstream PR draft for default_publishes seen_topics fixed40abefix(core): default_publishes of completion_promise must set completion_requested3c25a06docs: add upstream PR draft for default_publishes completion_requested fix3998962feat(core): add disallowed_tools, stale loop detection, and file-modification audit📊 Changes
18 files changed (+1663 additions, -4 deletions)
View changed files
📝
crates/ralph-bench/src/main.rs(+2 -0)📝
crates/ralph-cli/src/display.rs(+2 -0)📝
crates/ralph-cli/src/doctor.rs(+1 -0)📝
crates/ralph-cli/src/loop_runner.rs(+29 -0)📝
crates/ralph-core/src/config.rs(+29 -0)📝
crates/ralph-core/src/event_loop/loop_state.rs(+38 -0)📝
crates/ralph-core/src/event_loop/mod.rs(+219 -4)📝
crates/ralph-core/src/event_loop/tests.rs(+595 -0)📝
crates/ralph-core/src/hat_registry.rs(+79 -0)📝
crates/ralph-core/src/hatless_ralph.rs(+23 -0)📝
crates/ralph-core/src/summary_writer.rs(+6 -0)➕
docs/specs/context-window-utilization.md(+151 -0)➕
upstream-PRs/default-publishes-completion-requested-body.md(+120 -0)➕
upstream-PRs/default-publishes-completion-requested.md(+46 -0)➕
upstream-PRs/default-publishes-seen-topics-body.md(+91 -0)➕
upstream-PRs/default-publishes-seen-topics.md(+47 -0)➕
upstream-PRs/hat-scope-enforcement-body.md(+58 -0)➕
upstream-PRs/hat-scope-enforcement.md(+127 -0)📄 Description
Closes #194
Summary
Adds three engine-level mechanisms to prevent hat role violations and infinite loop cycling — Phase 2 of the loop cycling fix plan.
disallowed_toolsfield onHatConfigwith prompt-level enforcementscope_violationeventsProblem
Two bugs were observed during a ralph loop run:
Bug 1: Dispatcher implemented code (role violation)
The dispatcher hat read plan files and edited 12 source files despite instructions saying "Don't build anything yourself." Existing
enforce_hat_scopeonly validates event publishing, not tool usage. There's no mechanism to prevent a hat from using Edit/Write/Bash tools.Bug 2: 5 wasted iterations cycling after work done (~$1.7 burned)
After all work completed, the loop cycled between dispatcher and builder emitting the same events repeatedly:
The same
all.built→build.complete→all.builtpattern was also observed in a separate run.Changes
2A:
disallowed_toolsprompt-level enforcementcrates/ralph-core/src/config.rsdisallowed_tools: Vec<String>field onHatConfigcrates/ralph-core/src/hatless_ralph.rsdisallowed_toolsonHatInfo; TOOL RESTRICTIONS section injected in active hat promptsWhen a hat has
disallowed_toolsconfigured, the prompt includes a prominent section:Preset usage:
2B: Stale topic detection (cycle breaker)
crates/ralph-core/src/event_loop/loop_state.rslast_emitted_topicandconsecutive_same_topicfields;record_topic()tracks consecutive emissionscrates/ralph-core/src/event_loop/mod.rsTerminationReason::LoopStalevariant;check_termination()returnsLoopStalewhen same topic emitted 3+ timesWhen the same topic is emitted 3 or more times consecutively, the loop terminates with exit code 1 (
LoopStale). This catches theall.built→build.complete→all.builtcycle pattern.The tracking is done in
record_topic()which is called both fromprocess_events_from_jsonl()(agent-written events) andcheck_default_publishes()(auto-injected events), ensuring full coverage.2C: File-modification audit (hard enforcement)
crates/ralph-core/src/event_loop/mod.rsaudit_file_modifications()method called fromprocess_output()After each iteration, if the active hat has
EditorWriteindisallowed_tools, runsgit diff --stat HEADto detect unauthorized file modifications. If modifications are found, emits a<hat_id>.scope_violationevent on the bus.Presets can route this event to trigger corrective actions:
Exhaustive match updates
crates/ralph-cli/src/display.rsLoopStaleto termination displaycrates/ralph-cli/src/loop_runner.rsLoopStaleto history recording and merge queue statecrates/ralph-core/src/summary_writer.rsLoopStaleto summary status textcrates/ralph-bench/src/main.rsLoopStaleto benchmark result formattingTests
cargo test— full workspace passes (all existing tests + new field defaults)cargo build— clean compilationTest Plan
disallowed_tools: ['Edit', 'Write']on dispatcher → verify TOOL RESTRICTIONS section appears in promptLoopStaleterminationscope_violationevent emitted🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.