mirror of
https://github.com/mikeyobrien/ralph-orchestrator.git
synced 2026-04-24 22:55:57 +03:00
[PR #196] fix(core): record default_publishes topics in seen_topics for chain validation #191
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/ralph-orchestrator#191
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/196
Author: @arjhun-personal
Created: 2/25/2026
Status: 🔄 Open
Base:
main← Head:fix/default-publishes-seen-topics📝 Commits (6)
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 validation📊 Changes
12 files changed (+1150 additions, -4 deletions)
View changed files
📝
crates/ralph-bench/src/main.rs(+1 -0)📝
crates/ralph-cli/src/display.rs(+1 -0)📝
crates/ralph-cli/src/loop_runner.rs(+27 -0)📝
crates/ralph-core/src/config.rs(+21 -0)📝
crates/ralph-core/src/event_loop/loop_state.rs(+21 -0)📝
crates/ralph-core/src/event_loop/mod.rs(+126 -4)📝
crates/ralph-core/src/event_loop/tests.rs(+535 -0)📝
crates/ralph-core/src/hat_registry.rs(+79 -0)📝
crates/ralph-core/src/summary_writer.rs(+3 -0)➕
docs/specs/context-window-utilization.md(+151 -0)➕
upstream-PRs/hat-scope-enforcement-body.md(+58 -0)➕
upstream-PRs/hat-scope-enforcement.md(+127 -0)📄 Description
Fixes #187
Summary
Fixes an infinite loop caused by
check_default_publishesnot recording injected topics inseen_topics, makingrequired_eventschain validation permanently unsatisfiable.Bug
When a hat writes no events to JSONL and the orchestrator injects a fallback via
default_publishes, the event is published on the bus (triggering downstream hats correctly) but never recorded inseen_topics. If that topic is listed inrequired_events,LOOP_COMPLETEis rejected every iteration because the topic appears permanently missing — even though the event was successfully delivered and acted upon.This creates an unrecoverable infinite loop: the work is done, all tests pass, but the loop can never terminate.
Steps to Reproduce
Configure a preset with
required_eventsthat includes a topic delivered viadefault_publishes:Run a loop where the planner hat completes its work but does not explicitly emit
plan.draftin its JSONL output (the agent writes the plan file but doesn't emit the event tag).The orchestrator injects
plan.draftviacheck_default_publishes— the ReviewGate triggers correctly and the workflow proceeds through all remaining phases.When the final hat emits
LOOP_COMPLETE, the event loop rejects it:A
task.resumeevent is injected, but no hat can retroactively produceplan.draft. The loop repeats indefinitely untilmax_iterationsis exhausted.Root Cause
check_default_publishes(event_loop/mod.rs:1403) callsself.bus.publish()but does not callself.state.record_topic(). Topic recording only happens inprocess_events_from_jsonl(line 2157) for events parsed from the agent's JSONL output. Thedefault_publishescode path bypasses this entirely.Fix
One line added to
check_default_publishesto record the topic before publishing:Changes
crates/ralph-core/src/event_loop/mod.rsrecord_topic()call incheck_default_publishescrates/ralph-core/src/event_loop/tests.rsTests
Updated test (
test_default_publishes_injects_when_no_events):seen_topicscontains the default topic aftercheck_default_publishesNew regression test (
test_default_publishes_satisfies_required_events_for_completion):required_events: ["plan.draft", "all.built"]with a planner hat that hasdefault_publishes: "plan.draft"default_publishesinjectsplan.draft, thenall.builtarrives via JSONLLOOP_COMPLETEis accepted (previously would have been rejected indefinitely)Test Plan
cargo test -p ralph-core test_default_publishes— 4 tests pass (including new regression test)cargo test -p ralph-core test_chain_validation— 5 tests pass (no regressions)cargo test— full suite passes🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.