Verified on the live box
/config/.loopover.yml line 67 contains:
That is the global default private-config layer, applied to every repo. resolveEffectiveSettings merges as {...dbSettings, ...restManifestSettings} (src/signals/focus-manifest.ts ~572), so the manifest wins. packages/loopover-engine/src/focus-manifest.ts ~2620 parses both agentPaused and agentDryRun out of settings:.
Consequence, live right now: setting agent_dry_run=1 in the DB — via the dashboard, PUT /settings, loopover-mcp maintain, or the loopover_set_agent_dry_run MCP tool — is silently discarded on every read, for every repo. The tool reads the raw row, writes it back, and reports success (src/mcp/server.ts ~4870-4879); it never re-resolves effective settings. You would get a success message and ORB would keep making real GitHub writes.
Good news, also verified: agentPaused is not present in any live config layer, so the per-repo pause toggle is intact. The DB global freeze (global_agent_controls.frozen, currently 0) is re-read live at every action execution (src/services/agent-action-executor.ts ~276, ~903) and is a genuine immediate brake.
Why this happens
The shipped operator templates both contain the line: config/examples/loopover.full.yml ~1056 and .loopover.yml.example ~1042 each set agentPaused: false. Any operator who deploys the reference template as their global default permanently disables both kill switches for their whole fleet — and gets a success message every time they try to use them.
Test coverage is asymmetric: test/unit/mcp-automation-state.test.ts ~120 covers manifest-true over DB-false; the dangerous reverse direction is untested.
Fix
- Make the kill switches safest-wins, not last-writer-wins:
effective.agentPaused = dbSettings.agentPaused === true || manifest.settings.agentPaused === true (same for agentDryRun). A safety brake must never be disabled by a lower-precedence-intent layer.
- Remove
agentPaused: false / agentDryRun: false from both shipped templates — a template should never ship an explicit disable of a safety control.
- Make
setAgentPaused/setAgentDryRun re-resolve effective settings after writing and loudly warn when the effective value disagrees with what was just written.
- Remove the line from our own
/config/.loopover.yml once (1) lands (harmless afterwards, but it is currently load-bearing).
Acceptance
- With
agentDryRun: false in a manifest layer, setting dry-run in the DB still takes effect.
- Toggling either switch and immediately reading effective settings shows the new value or an explicit conflict error.
Verified on the live box
/config/.loopover.ymlline 67 contains:That is the global default private-config layer, applied to every repo.
resolveEffectiveSettingsmerges as{...dbSettings, ...restManifestSettings}(src/signals/focus-manifest.ts~572), so the manifest wins.packages/loopover-engine/src/focus-manifest.ts~2620 parses bothagentPausedandagentDryRunout ofsettings:.Consequence, live right now: setting
agent_dry_run=1in the DB — via the dashboard,PUT /settings,loopover-mcp maintain, or theloopover_set_agent_dry_runMCP tool — is silently discarded on every read, for every repo. The tool reads the raw row, writes it back, and reports success (src/mcp/server.ts~4870-4879); it never re-resolves effective settings. You would get a success message and ORB would keep making real GitHub writes.Good news, also verified:
agentPausedis not present in any live config layer, so the per-repo pause toggle is intact. The DB global freeze (global_agent_controls.frozen, currently0) is re-read live at every action execution (src/services/agent-action-executor.ts~276, ~903) and is a genuine immediate brake.Why this happens
The shipped operator templates both contain the line:
config/examples/loopover.full.yml~1056 and.loopover.yml.example~1042 each setagentPaused: false. Any operator who deploys the reference template as their global default permanently disables both kill switches for their whole fleet — and gets a success message every time they try to use them.Test coverage is asymmetric:
test/unit/mcp-automation-state.test.ts~120 covers manifest-trueover DB-false; the dangerous reverse direction is untested.Fix
effective.agentPaused = dbSettings.agentPaused === true || manifest.settings.agentPaused === true(same foragentDryRun). A safety brake must never be disabled by a lower-precedence-intent layer.agentPaused: false/agentDryRun: falsefrom both shipped templates — a template should never ship an explicit disable of a safety control.setAgentPaused/setAgentDryRunre-resolve effective settings after writing and loudly warn when the effective value disagrees with what was just written./config/.loopover.ymlonce (1) lands (harmless afterwards, but it is currently load-bearing).Acceptance
agentDryRun: falsein a manifest layer, setting dry-run in the DB still takes effect.