Configured OpenClaw heartbeat interval is lost during managed rebuild
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
## Investigation summary
- `NEMOCLAW_AGENT_HEARTBEAT_EVERY=2m` reaches the managed startup profile, configuration environment, and `generate-openclaw-config.mts`.
- The generated `agents.defaults.heartbeat.every` is `2m`; OpenClaw 2026.7.1 resolves that exact config to 120000 ms.
- During state restore, `mergeOpenClawRestoredConfig()` overlays the backed-up `agents` tree and re-owns only `agents.defaults.model.primary`.
- A backup with no heartbeat or an older interval can therefore replace the freshly generated profile-owned heartbeat during rebuild.
- Direct generation tests cover the input but no lifecycle test binds the startup profile through state restore to the effective OpenClaw interval.
## Description
The documented OpenClaw heartbeat interval is not preserved across NemoClaw's managed state-restore path. A sandbox configured with `NEMOCLAW_AGENT_HEARTBEAT_EVERY=2m` can run OpenClaw with its 30-minute default after a supported rebuild or reconciliation restores an older `openclaw.json`.
The fresh managed-startup configuration must own `agents.defaults.heartbeat`, including configured presence or intentional absence, while the remaining durable `agents` settings continue to restore from the backup.
This is a defect in the supported heartbeat behavior established by #2880 and #3158. It does not change the heartbeat interface or add a new product surface.
## Reproduction steps
1. Onboard an OpenClaw sandbox with `NEMOCLAW_AGENT_HEARTBEAT_EVERY=2m`.
2. Confirm the startup profile and freshly generated `openclaw.json` contain `agents.defaults.heartbeat.every = "2m"`.
3. Preserve an older state snapshot whose `agents.defaults.heartbeat` is absent or set to another interval.
4. Run the supported rebuild/state-restore path.
5. Inspect the restored `openclaw.json` and the gateway's `heartbeat: started` record.
Current result: the backup's heartbeat state wins and OpenClaw can report `intervalMs=1800000`.
Expected result: the fresh profile wins and OpenClaw reports `intervalMs=120000`; the value survives supported rebuild, restart, and config reconciliation.
## Acceptance criteria
- A focused merge regression proves a backup with an absent, default, or different heartbeat cannot replace a fresh `2m` heartbeat.
- The fresh config also owns intentional heartbeat absence so a stale backup cannot re-enable it.
- Unrelated durable `agents` settings still restore.
- Managed-image lifecycle evidence binds the startup profile receipt to the generated config and OpenClaw's effective 120000 ms interval.
- Supported rebuild and restart retain the same effective interval and config-integrity hash.
- A first heartbeat can run within the configured interval's declared bound.
- No credential, policy, channel, MCP, or provider ownership rule is weakened.
## State and security boundaries
- Fresh profile `2m`, backup absent/different: fresh heartbeat must win.
- Fresh profile omits heartbeat, backup has a value: fresh omission must win.
- Malformed heartbeat input: existing pre-mutation validation must continue to reject it.
- Restore failure: the existing fail-closed restore and rollback behavior remains unchanged.
- The change is limited to ownership of the non-secret heartbeat subtree in the OpenClaw config merger.
## Environment
- Reproduced consumer version: NemoClaw `5ee38b5d555e5d59fce9570e623d2f09071075c1` (`v0.0.113-102-g5ee38b5d5`)
- Current `main` checked: `41bb231dabdd8f2305abb985e80ff0e2ba09c28e`
- Managed OpenClaw package: `2026.7.1`
- OpenShell-managed Docker sandbox
## Debug output
Sanitized runtime evidence reports `heartbeat: started` with `intervalMs=1800000` despite the documented `2m` onboarding input. Source-level reproduction isolates the first overwrite to the selective `openclaw.json` state merger. No credentials, endpoints, sandbox identifiers, or raw configuration are included.
## Non-goals
- Changing the public heartbeat environment variables or their format.
- Changing Remy's separate behavior of restarting its gateway from inside an MCP request.
- A host-local patch or credential change.
- [x] I confirmed this bug is reproducible
- [x] I searched existing issues and this is not a duplicate
Contributor guide
Assessment
This issue has not been assessed yet.