Skip to content

fix(heartbeat): make phase scheduling active-hours-aware (#75487)#75597

Merged
clawsweeper[bot] merged 8 commits intomainfrom
ak/fix-75487-heartbeat-active-hours-tz
May 2, 2026
Merged

fix(heartbeat): make phase scheduling active-hours-aware (#75487)#75597
clawsweeper[bot] merged 8 commits intomainfrom
ak/fix-75487-heartbeat-active-hours-tz

Conversation

@amknight
Copy link
Copy Markdown
Member

@amknight amknight commented May 1, 2026

Summary

Fixes #75487.

computeNextHeartbeatPhaseDueMs computes next-fire times using pure UTC-epoch modular arithmetic. activeHours was only checked as a runtime execution guard in runHeartbeatOnce — when a quiet-hours slot was skipped, advanceAgentSchedule computed the next slot (also in UTC) which could also be in quiet hours.

This caused:

  • Wasted quiet-hours ticks (skipped at runtime but still consumed/advanced)
  • Long dormant gaps after gateway restarts during quiet hours
  • With non-UTC timezones like Asia/Shanghai, multiple consecutive phase slots falling outside the active window before the next in-window slot

Changes

src/infra/heartbeat-schedule.ts

  • Added seekNextActivePhaseDueMs() — takes a starting slot and an isActive predicate, iterates forward through phase-aligned slots (up to a 7-day horizon), and returns the first in-window slot. Falls back to the raw slot if no active slot is found within the horizon (so the runtime guard can still gate execution).

src/infra/heartbeat-runner.ts

  • advanceAgentSchedule now wraps the computed next-due time with seekNextActivePhaseDueMs, using isWithinActiveHours as the predicate.
  • updateConfig initial scheduling also seeks forward to the first in-window slot on startup/config reload.

@openclaw-barnacle openclaw-barnacle Bot added size: M maintainer Maintainer-authored PR labels May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Codex review: passed.

Summary
The PR adds active-hours-aware heartbeat phase seeking, wires runner scheduling and config reloads through it, adds scheduler/e2e coverage, and records the user-facing fix in the changelog.

Reproducibility: yes. Current main can be reproduced with a 4h heartbeat and an Asia/Shanghai active-hours window during a quiet-hours restart: main arms raw UTC-phase slots and only skips when the timer fires.

Next step before merge
No repair job is needed; the automerge-opted PR has a clean source review, clean mergeability, and green exact-head check runs.

Security
Cleared: The diff is limited to heartbeat scheduling/runtime TypeScript, tests, and changelog text, with no dependency, workflow, permission, secret, install, build, release, or package-resolution changes.

Review details

Best possible solution:

Land this PR through the existing automerge path, keeping the runtime active-hours guard as the final backstop.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main can be reproduced with a 4h heartbeat and an Asia/Shanghai active-hours window during a quiet-hours restart: main arms raw UTC-phase slots and only skips when the timer fires.

Is this the best way to solve the issue?

Yes. The PR is the narrow scheduler-layer fix: it seeks through phase-aligned slots with the existing active-hours predicate, handles config/timezone changes, and leaves the runtime guard intact.

What I checked:

Likely related people:

  • odysseus0: The stable per-agent heartbeat phase scheduler involved here appears in commit 9a4a9a5, which the GitHub commit metadata credits and reviews through @odysseus0. (role: introduced phase scheduling behavior; confidence: high; commits: 9a4a9a5993cc; files: src/infra/heartbeat-schedule.ts, src/infra/heartbeat-runner.ts, src/infra/heartbeat-schedule.test.ts)
  • steipete: Recent main history shows adjacent heartbeat runner/scheduler maintenance around wake intent, cron/nested-lane deferral, and schedule drift behavior. (role: recent heartbeat runtime maintainer; confidence: high; commits: c06739d773da, f5e7557c70c1, 733f7af92b01; files: src/infra/heartbeat-runner.ts, src/infra/heartbeat-runner.scheduler.test.ts)
  • adhitShet: Prior active-hours fixes changed zero-width window and 24:00 sentinel semantics that this PR reuses through isWithinActiveHours. (role: active-hours behavior contributor; confidence: medium; commits: ae4907ce6e3d, 57f0ac21e9ea; files: src/infra/heartbeat-active-hours.ts, src/infra/heartbeat-active-hours.test.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 0fad53a19281.

@amknight
Copy link
Copy Markdown
Member Author

amknight commented May 1, 2026

/clawsweeper automerge

@clawsweeper clawsweeper Bot added the clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge label May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

🦞🦞
ClawSweeper merged this PR after the passing review.

Source: clawsweeper[bot]
Feedback: structured ClawSweeper verdict: pass (sha=02a1283c933f1f9294f54d7035e31aeb83eca736)
Merge status: merged by ClawSweeper automerge
Merged at: 2026-05-02T20:17:54Z
Merge commit: 10448a0ad14c

What merged:

  • The PR adds active-hours-aware heartbeat phase seeking, wires runner scheduling and config reloads through it, adds scheduler/e2e coverage, and records the user-facing fix in the changelog.
  • Reproducibility: yes. Current main can be reproduced with a 4h heartbeat and an Asia/Shanghai active-hours window during a quiet-hours restart: main arms raw UTC-phase slots and only skips when the timer fires.

Fixups included:

  • Included follow-up commit: fix(heartbeat): recompute schedule when activeHours config changes vi…
  • Included follow-up commit: fix(heartbeat): add iteration cap to active-hours seek + edge-case tests
  • Included follow-up commit: chore: clean up redundant code comments
  • Included follow-up commit: fix(heartbeat): make phase scheduling active-hours-aware (Heartbeat activeHours timezone ignored — phase schedules based on UTC, not configured timezone #75487)
  • Included follow-up commit: fix(clawsweeper): address review for automerge-openclaw-openclaw-7559…

The automerge loop is complete.

Automerge progress:

  • 2026-05-01 12:38:10 UTC repair queued `cb4e2aeaa07f` (autonomous) Run: https://github.com/openclaw/clawsweeper/actions/runs/25214532388
  • 2026-05-01 12:56:23 UTC repair completed (no branch change) in 6m 11s Run: https://github.com/openclaw/clawsweeper/actions/runs/25214532388 validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, docs [check:changed] src/infra/heartbeat-active-hours.test.ts: core test...
  • 2026-05-01 19:06:40 UTC repair queued `cb4e2aeaa07f` (autonomous) Run: https://github.com/openclaw/clawsweeper/actions/runs/25228686618
  • 2026-05-01 19:14:26 UTC repair completed (no branch change) in 5m 28s Run: https://github.com/openclaw/clawsweeper/actions/runs/25228686618 validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, docs [check:changed] src/infra/heartbeat-active-hours.ts: core productio...
  • 2026-05-02 19:31:57 UTC review queued [`cb4e2aeaa07f`](https://github.com/openclaw/openclaw/commit/cb4e2aeaa07f9be178f1ad7950fcc22b40c02f4b) (queued)
  • 2026-05-02 19:33:03 UTC repair queued [`cb4e2aeaa07f`](https://github.com/openclaw/openclaw/commit/cb4e2aeaa07f9be178f1ad7950fcc22b40c02f4b) (autonomous) Run: https://github.com/openclaw/clawsweeper/actions/runs/25260057123
  • 2026-05-02 19:48:24 UTC repair completed [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (branch updated) in 12m 49s Run: https://github.com/openclaw/clawsweeper/actions/runs/25260057123 initial automerge rebase is delegated to Codex repair
  • 2026-05-02 19:48:24 UTC review queued [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (after repair)
  • 2026-05-01 11:37:10 UTC review queued [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (queued)
  • 2026-05-02 19:50:42 UTC repair queued [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (autonomous) Run: https://github.com/openclaw/clawsweeper/actions/runs/25260394910
  • 2026-05-02 19:53:23 UTC review passed [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (structured ClawSweeper verdict: pass (sha=ce0e56329fe1e26eb9e3080a0974a49a3b7e2...)
  • 2026-05-02 19:56:53 UTC review queued [`ce0e56329fe1`](https://github.com/openclaw/openclaw/commit/ce0e56329fe1e26eb9e3080a0974a49a3b7e2360) (queued)
  • 2026-05-02 20:13:35 UTC repair completed [`02a1283c933f`](https://github.com/openclaw/openclaw/commit/02a1283c933f1f9294f54d7035e31aeb83eca736) (branch updated) in 20m 15s Run: https://github.com/openclaw/clawsweeper/actions/runs/25260394910 initial automerge rebase is delegated to Codex repair
  • 2026-05-02 20:13:34 UTC review queued [`02a1283c933f`](https://github.com/openclaw/openclaw/commit/02a1283c933f1f9294f54d7035e31aeb83eca736) (after repair)
  • 2026-05-02 20:17:41 UTC review passed [`02a1283c933f`](https://github.com/openclaw/openclaw/commit/02a1283c933f1f9294f54d7035e31aeb83eca736) (structured ClawSweeper verdict: pass (sha=02a1283c933f1f9294f54d7035e31aeb83eca...)
  • 2026-05-02 20:17:55 UTC merged [`02a1283c933f`](https://github.com/openclaw/openclaw/commit/02a1283c933f1f9294f54d7035e31aeb83eca736) (merged by ClawSweeper automerge)

@amknight amknight marked this pull request as ready for review May 1, 2026 11:39
@clawsweeper clawsweeper Bot force-pushed the ak/fix-75487-heartbeat-active-hours-tz branch from cb4e2ae to ce0e563 Compare May 2, 2026 19:48
@clawsweeper clawsweeper Bot force-pushed the ak/fix-75487-heartbeat-active-hours-tz branch from ce0e563 to 02a1283 Compare May 2, 2026 20:13
@clawsweeper clawsweeper Bot merged commit 10448a0 into main May 2, 2026
87 checks passed
@clawsweeper clawsweeper Bot deleted the ak/fix-75487-heartbeat-active-hours-tz branch May 2, 2026 20:17
vincentkoc added a commit that referenced this pull request May 2, 2026
* 'main' of https://github.com/openclaw/openclaw:
  Wizard: bound hatch TUI timeout (#76241)
  fix(cli): reject codex simple-completion probes
  fix: memoize plugin descriptor config keys (#76240)
  fix(heartbeat): make phase scheduling active-hours-aware (#75487) (#75597)
lxe pushed a commit to lxe/openclaw that referenced this pull request May 6, 2026
) (openclaw#75597)

Summary:
- The PR adds active-hours-aware heartbeat phase seeking, wires runner scheduling and config reloads through it, adds scheduler/e2e coverage, and records the user-facing fix in the changelog.
- Reproducibility: yes. Current main can be reproduced with a `4h` heartbeat and an `Asia/Shanghai` active-hours window during a quiet-hours restart: main arms raw UTC-phase slots and only skips when the timer fires.

ClawSweeper fixups:
- Included follow-up commit: fix(heartbeat): recompute schedule when activeHours config changes vi…
- Included follow-up commit: fix(heartbeat): add iteration cap to active-hours seek + edge-case tests
- Included follow-up commit: chore: clean up redundant code comments
- Included follow-up commit: fix(heartbeat): make phase scheduling active-hours-aware (openclaw#75487)
- Included follow-up commit: fix(clawsweeper): address review for automerge-openclaw-openclaw-7559…

Validation:
- ClawSweeper review passed for head 02a1283.
- Required merge gates passed before the squash merge.

Prepared head SHA: 02a1283
Review: openclaw#75597 (comment)

Co-authored-by: Alex Knight <aknight@atlassian.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
) (openclaw#75597)

Summary:
- The PR adds active-hours-aware heartbeat phase seeking, wires runner scheduling and config reloads through it, adds scheduler/e2e coverage, and records the user-facing fix in the changelog.
- Reproducibility: yes. Current main can be reproduced with a `4h` heartbeat and an `Asia/Shanghai` active-hours window during a quiet-hours restart: main arms raw UTC-phase slots and only skips when the timer fires.

ClawSweeper fixups:
- Included follow-up commit: fix(heartbeat): recompute schedule when activeHours config changes vi…
- Included follow-up commit: fix(heartbeat): add iteration cap to active-hours seek + edge-case tests
- Included follow-up commit: chore: clean up redundant code comments
- Included follow-up commit: fix(heartbeat): make phase scheduling active-hours-aware (openclaw#75487)
- Included follow-up commit: fix(clawsweeper): address review for automerge-openclaw-openclaw-7559…

Validation:
- ClawSweeper review passed for head 02a1283.
- Required merge gates passed before the squash merge.

Prepared head SHA: 02a1283
Review: openclaw#75597 (comment)

Co-authored-by: Alex Knight <aknight@atlassian.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* 'main' of https://github.com/openclaw/openclaw:
  Wizard: bound hatch TUI timeout (openclaw#76241)
  fix(cli): reject codex simple-completion probes
  fix: memoize plugin descriptor config keys (openclaw#76240)
  fix(heartbeat): make phase scheduling active-hours-aware (openclaw#75487) (openclaw#75597)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Heartbeat activeHours timezone ignored — phase schedules based on UTC, not configured timezone

1 participant