fix(heartbeat): emit the documented quiet-hours skip event (#124542)

The active-hours guard returned skipped/quiet-hours without emitting a
heartbeat event, while every sibling skip in the same stage emits one.
'openclaw system heartbeat last' and the troubleshooting docs promise
reason=quiet-hours is observable; the silent return hid the window from
operators. Emit the same skipped event the siblings do.
This commit is contained in:
Peter Steinberger
2026-08-16 05:49:47 -07:00
committed by GitHub
parent 458923cb03
commit 4e652f9fac
2 changed files with 12 additions and 0 deletions
+8
View File
@@ -184,6 +184,14 @@ export async function resolveHeartbeatWakeStage(opts: HeartbeatRunOptions) {
wakeSource !== "cron" &&
!isWithinActiveHours(cfg, heartbeat, startedAt)
) {
// Documented observable skip (`system heartbeat last` / troubleshooting
// docs promise reason=quiet-hours); every sibling skip past this point
// emits, so a silent return here hides the window from operators.
emitHeartbeatEvent({
status: "skipped",
reason: "quiet-hours",
durationMs: Date.now() - startedAt,
});
return { kind: "skipped", reason: "quiet-hours" } as const;
}
@@ -23,6 +23,7 @@ import {
} from "../test-utils/channel-plugins.js";
import { typedCases } from "../test-utils/typed-cases.js";
import { normalizeSessionDeliveryState } from "../utils/delivery-context.shared.js";
import { getLastHeartbeatEvent, resetHeartbeatEventsForTest } from "./heartbeat-events.js";
import {
type HeartbeatDeps,
isHeartbeatEnabledForAgent,
@@ -337,6 +338,7 @@ beforeAll(async () => {
beforeEach(() => {
resetSystemEventsForTest();
resetHeartbeatEventsForTest();
if (testRegistry) {
setActivePluginRegistry(testRegistry);
}
@@ -862,6 +864,8 @@ describe("runHeartbeatOnce", () => {
if (res.status === "skipped") {
expect(res.reason).toBe("quiet-hours");
}
// Documented observable skip: `system heartbeat last` must show the window.
expect(getLastHeartbeatEvent()).toMatchObject({ status: "skipped", reason: "quiet-hours" });
});
it("skips a routeless interval poll before the agent run", async () => {