test: expand reminder guard fail-closed coverage (#32255) (thanks @scoootscooob)

This commit is contained in:
Peter Steinberger
2026-03-02 23:34:54 +00:00
parent 5868344ade
commit 73e08ed7b0
2 changed files with 45 additions and 2 deletions

View File

@@ -58,6 +58,7 @@ Docs: https://docs.openclaw.ai
- Gateway/Security canonicalization hardening: decode plugin route path variants to canonical fixpoint (with bounded depth), fail closed on canonicalization anomalies, and enforce gateway auth for deeply encoded `/api/channels/*` variants to prevent alternate-path auth bypass through plugin handlers. Thanks @tdjackey for reporting.
- Security/Prompt spoofing hardening: stop injecting queued runtime events into user-role prompt text, route them through trusted system-prompt context, and neutralize inbound spoof markers like `[System Message]` and line-leading `System:` in untrusted message content. (#30448)
- Auto-reply/followup queue: avoid stale callback reuse across idle-window restarts by caching the followup runner only when a drain actually starts, preserving enqueue ordering after empty-finalize paths. (#31902) Thanks @Lanfei.
- Auto-reply/reminder guard note suppression: when a turn makes reminder-like commitments but schedules no new cron jobs, suppress the unscheduled-reminder warning note only if an enabled cron already exists for the same session; keep warnings for unrelated sessions, disabled jobs, or unreadable cron store paths. (#32255) Thanks @scoootscooob.
- Cron/HEARTBEAT_OK summary leak: suppress fallback main-session enqueue for heartbeat/internal ack summaries in isolated announce mode so `HEARTBEAT_OK` noise never appears in user chat while real summaries still forward. (#32093) Thanks @scoootscooob.
- Cron/isolated announce heartbeat suppression: treat multi-payload runs as skippable when any payload is a heartbeat ack token and no payload has media, preventing internal narration + trailing `HEARTBEAT_OK` from being delivered to users. (#32131) Thanks @adhishthite.
- Sessions/lock recovery: reclaim orphan legacy same-PID lock files missing `starttime` when no in-process lock ownership exists, avoiding false lock timeouts after PID reuse while preserving active lock safety checks. (#32081) Thanks @bmendonca3.

View File

@@ -1108,7 +1108,7 @@ describe("runReplyAgent messaging tool suppression", () => {
});
describe("runReplyAgent reminder commitment guard", () => {
function createRun() {
function createRun(params?: { sessionKey?: string; omitSessionKey?: boolean }) {
const typing = createMockTypingController();
const sessionCtx = {
Provider: "telegram",
@@ -1156,7 +1156,7 @@ describe("runReplyAgent reminder commitment guard", () => {
isStreaming: false,
typing,
sessionCtx,
sessionKey: "main",
...(params?.omitSessionKey ? {} : { sessionKey: params?.sessionKey ?? "main" }),
defaultModel: "anthropic/claude-opus-4-5",
resolvedVerboseLevel: "off",
isNewSession: false,
@@ -1273,6 +1273,48 @@ describe("runReplyAgent reminder commitment guard", () => {
text: "I'll check back in an hour.\n\nNote: I did not schedule a reminder in this turn, so this will not trigger automatically.",
});
});
it("still appends guard note when sessionKey is missing", async () => {
loadCronStoreMock.mockResolvedValueOnce({
version: 1,
jobs: [
{
id: "existing-job",
name: "monitor-task",
enabled: true,
sessionKey: "main",
createdAtMs: Date.now() - 60_000,
updatedAtMs: Date.now() - 60_000,
},
],
});
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "I'll ping you later." }],
meta: {},
successfulCronAdds: 0,
});
const result = await createRun({ omitSessionKey: true });
expect(result).toMatchObject({
text: "I'll ping you later.\n\nNote: I did not schedule a reminder in this turn, so this will not trigger automatically.",
});
});
it("still appends guard note when cron store read fails", async () => {
loadCronStoreMock.mockRejectedValueOnce(new Error("store read failed"));
runEmbeddedPiAgentMock.mockResolvedValueOnce({
payloads: [{ text: "I'll remind you after lunch." }],
meta: {},
successfulCronAdds: 0,
});
const result = await createRun({ sessionKey: "main" });
expect(result).toMatchObject({
text: "I'll remind you after lunch.\n\nNote: I did not schedule a reminder in this turn, so this will not trigger automatically.",
});
});
});
describe("runReplyAgent fallback reasoning tags", () => {