v2026.05.20.2 — GoalRunner priority + revision-storm guard + arbiter default ON + kill switch
Patch on top of v2026.05.20.1.
Triggered by a senior-pass review of a 5h33m AlphaScala log that showed the agent functionally idle despite concurrency machinery being correct. Four holes closed.
What's fixed
1. GoalRunner now runs at GOAL priority
The autonomous goal-runner was acquiring AGENT_LOOP at USER priority (0) because agent.run(prompt) defaults to is_user_input=True. It competed with operator chat for the top slot and starved everything below — MIND preempted on every cycle, SCHEDULED_CADENCE waited 1h57m. TaskSource.GOAL (priority 5) was always meant for this. One-line fix: submit_task(TaskSource.GOAL, prompt).
2. Revision-storm guard
A goal stuck in self-contradictory revisions ("Day 1 incomplete BUT checkpoint 8 says Day 1 verified") was looping for hours with zero forward progress. New revisions_without_progress counter pauses the goal after 3 revisions without any checkpoint completing.
3. Arbiter default flipped to True
The legacy free-form mind prompt produces analysis-paralysis loops ("12 steps of thinking about collecting 25 sources" with no tool action). Phase 3 arbiter — forced pick from a scored menu — was hidden behind a default-off flag.
Existing operators on ./update.sh get the new value applied to their config.yaml automatically via elophanto config migrate.
4. Operator kill switch — elophanto stop / elophanto resume 🆕
The killer feature for this patch. Operator reported: "i cannot stop the goal as a user. that makes it unusable completely."
elophanto stop # halt mind + scheduler + agent.run loops at next safe checkpoint
elophanto stop --hard # also cancel active goals + disable cron schedules
elophanto resume # clear the sentinel; loops tick againWrites a <data_dir>/STOP sentinel file that every in-process loop polls at safe checkpoints (between rounds, between wakeups, before scheduler dispatch). No mid-tool-call interruption, no browser corruption. Works whether or not the gateway is up, survives restarts, rm data/STOP is the manual fallback.
Tests
268+ focused green. Ruff + mypy clean.
Causation note
AGENT_LOOP serialization was always working; the GoalRunner priority bug made it look like it wasn't. The arbiter was always available; default-off made it the operator's homework. Mind/scheduler/goal-runner all had pause primitives; without a cross-subsystem kill, none was reachable from outside the process.
Commits
bc059e4GoalRunner uses GOAL priority + bound revision storms + arbiter default ON1b588c9Kill switch: data/STOP sentinel +elophanto stop/resumeCLId3c864bRelease v2026.05.20.2
Full diff: v2026.05.20.1...v2026.05.20.2