A paused engine with nothing running derived executorState "idle", so the footer badge was indistinguishable from a healthy engine waiting for work. That is exactly the state a pause settles into once in-flight tasks drain: triage and planning stall while the board keeps moving, with the pause only visible by opening the Engine Control menu. Pause state now dominates run state; the adjacent counters still report throughput. In the CLI TUI, the global `t` (Git view) branch returned before the Utilities dispatch in the same key handler, so the advertised "[t] Toggle Engine Pause" was unreachable dead UI. It now yields when Utilities owns input, and because the shortcut can stop the board, pausing takes a second `t` within 5s while resuming stays single-press. Tests assert the invariant across the whole state matrix (both pause flags x 0/1/5 running), not just the zero-running repro, plus the TUI routing, the two-press pause, single-press resume, and re-arm behavior. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
48 lines
1.9 KiB
TypeScript
48 lines
1.9 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { deriveExecutorState } from "../hooks/useExecutorStats";
|
|
|
|
/*
|
|
FNXC:EngineControls 2026-07-24-18:35:
|
|
Regression cover for the pause-reads-as-idle bug: a paused engine with nothing
|
|
running rendered the same "Idle" footer badge as a healthy engine waiting for
|
|
work, so operators could not tell why triage/planning had stopped. The invariant
|
|
under test is pause-dominates-run-state across the whole matrix, not just the
|
|
reported zero-running repro — asserted at every running count and against both
|
|
pause flags, since globalPause must keep out-ranking enginePaused.
|
|
*/
|
|
describe("deriveExecutorState", () => {
|
|
it("reports paused at every running count, including zero", () => {
|
|
for (const runningTaskCount of [0, 1, 5]) {
|
|
expect(deriveExecutorState(false, true, runningTaskCount)).toBe("paused");
|
|
}
|
|
});
|
|
|
|
it("reports stopped whenever globalPause is set, outranking enginePaused", () => {
|
|
for (const enginePaused of [false, true]) {
|
|
for (const runningTaskCount of [0, 1, 5]) {
|
|
expect(deriveExecutorState(true, enginePaused, runningTaskCount)).toBe("stopped");
|
|
}
|
|
}
|
|
});
|
|
|
|
it("reports idle only when unpaused with nothing running", () => {
|
|
expect(deriveExecutorState(false, false, 0)).toBe("idle");
|
|
});
|
|
|
|
it("reports running when unpaused with work in flight", () => {
|
|
expect(deriveExecutorState(false, false, 1)).toBe("running");
|
|
expect(deriveExecutorState(false, false, 5)).toBe("running");
|
|
});
|
|
|
|
it("never reports idle while either pause flag is set", () => {
|
|
for (const globalPause of [false, true]) {
|
|
for (const enginePaused of [false, true]) {
|
|
if (!globalPause && !enginePaused) continue;
|
|
for (const runningTaskCount of [0, 1, 5]) {
|
|
expect(deriveExecutorState(globalPause, enginePaused, runningTaskCount)).not.toBe("idle");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|