Summary
The gateway health-monitor polling interval is hardcoded at 5 minutes (DEFAULT_CHECK_INTERVAL_MS = 5 * 6e4) and there is no config path to override it. The Zod schema for per-channel healthMonitor is .strict() and only accepts { enabled: boolean }, so any attempt to set an interval via openclaw.json is rejected at validation.
Evidence (OpenClaw 2026.4.5, commit 3e72c03)
```js
// dist/server-Cv5hzFG4.js
const DEFAULT_CHECK_INTERVAL_MS = 5 * 6e4; // 300000ms — hardcoded
const DEFAULT_MONITOR_STARTUP_GRACE_MS = 6e4; // 60s — hardcoded
const { checkIntervalMs = DEFAULT_CHECK_INTERVAL_MS, ... } = deps;
```
```js
// dist/zod-schema.providers-core-COgcDZGS.js
const ChannelHealthMonitorSchema =
z.object({ enabled: z.boolean().optional() }).strict().optional();
```
checkIntervalMs is accepted by the constructor's deps parameter but no user-facing config key threads through to it. Operators have no way to tune it without patching node_modules, which gets clobbered on every weekly-auto-update.
Why this matters
When a channel goes stale (commonly Discord via @buape/carbon keepalive vs blocking interaction handlers), recovery latency = up to 5 minutes + reconnect. For users running OpenClaw as a primary bot platform, that's a 5-minute window where slash commands silently fail. A 60-second interval would shrink the window 5x with negligible CPU overhead (one socket health check per channel per minute).
Proposed change
Extend ChannelHealthMonitorSchema to accept an optional checkIntervalMs (or checkIntervalSeconds):
```ts
const ChannelHealthMonitorSchema = z.object({
enabled: z.boolean().optional(),
checkIntervalMs: z.number().int().min(10000).max(900000).optional(),
}).strict().optional();
```
Thread it through the gateway bootstrap so deps.checkIntervalMs is sourced from config when present, falling back to DEFAULT_CHECK_INTERVAL_MS. Same treatment would be useful for monitorStartupGraceMs and channelConnectGraceMs while you're in there.
Operator context
- OpenClaw 2026.4.5 on macOS (Mac Mini, launchd-supervised)
- 4 active channels: Discord, WhatsApp, Telegram, voice-call
- Discord stale-socket cadence over a 24h window: 13 events, intervals 35min–4h, all auto-recovered by health-monitor
- Carbon keepalive issue is the underlying cause (separate problem, not asking to fix here)
- Mitigation today: live with 5min downtime windows
Related (not duplicates)
This issue is narrower: just expose the polling interval in the schema. Trivial change, unblocks a class of operator tuning that currently requires patching the bundle.
Summary
The gateway health-monitor polling interval is hardcoded at 5 minutes (
DEFAULT_CHECK_INTERVAL_MS = 5 * 6e4) and there is no config path to override it. The Zod schema for per-channelhealthMonitoris.strict()and only accepts{ enabled: boolean }, so any attempt to set an interval viaopenclaw.jsonis rejected at validation.Evidence (OpenClaw 2026.4.5, commit 3e72c03)
```js
// dist/server-Cv5hzFG4.js
const DEFAULT_CHECK_INTERVAL_MS = 5 * 6e4; // 300000ms — hardcoded
const DEFAULT_MONITOR_STARTUP_GRACE_MS = 6e4; // 60s — hardcoded
const { checkIntervalMs = DEFAULT_CHECK_INTERVAL_MS, ... } = deps;
```
```js
// dist/zod-schema.providers-core-COgcDZGS.js
const ChannelHealthMonitorSchema =
z.object({ enabled: z.boolean().optional() }).strict().optional();
```
checkIntervalMsis accepted by the constructor'sdepsparameter but no user-facing config key threads through to it. Operators have no way to tune it without patchingnode_modules, which gets clobbered on everyweekly-auto-update.Why this matters
When a channel goes stale (commonly Discord via
@buape/carbonkeepalive vs blocking interaction handlers), recovery latency = up to 5 minutes + reconnect. For users running OpenClaw as a primary bot platform, that's a 5-minute window where slash commands silently fail. A 60-second interval would shrink the window 5x with negligible CPU overhead (one socket health check per channel per minute).Proposed change
Extend
ChannelHealthMonitorSchemato accept an optionalcheckIntervalMs(orcheckIntervalSeconds):```ts
const ChannelHealthMonitorSchema = z.object({
enabled: z.boolean().optional(),
checkIntervalMs: z.number().int().min(10000).max(900000).optional(),
}).strict().optional();
```
Thread it through the gateway bootstrap so
deps.checkIntervalMsis sourced from config when present, falling back toDEFAULT_CHECK_INTERVAL_MS. Same treatment would be useful formonitorStartupGraceMsandchannelConnectGraceMswhile you're in there.Operator context
Related (not duplicates)
staleEventThresholdMsspecificallyThis issue is narrower: just expose the polling interval in the schema. Trivial change, unblocks a class of operator tuning that currently requires patching the bundle.