Skip to content

fix(act): self-re-arm DeferTimer on a premature ceiling clamp (ACT-1288) - #1290

Merged
Rotorsoft merged 1 commit into
masterfrom
act-1288-defertimer-rearm
Jul 19, 2026
Merged

fix(act): self-re-arm DeferTimer on a premature ceiling clamp (ACT-1288)#1290
Rotorsoft merged 1 commit into
masterfrom
act-1288-defertimer-rearm

Conversation

@Rotorsoft

Copy link
Copy Markdown
Owner

Summary

Fixes #1288. DeferTimer.schedule() clamps a wait to the 32-bit setTimeout ceiling (~24.8 days) and its comment promised on_wake re-schedules for the remaining span — but the drain consumer's on_wake only sets _armed, and its arm-triggered drain early-returns before the :538 re-schedule (the stream is still store-excluded by deferred_at). So a defer / autoclose cooldown past the ceiling (after: { days: 90 }) fired once prematurely, then never re-armed: the precise wake was lost and the entry leaked in the parked set.

Fix

Self-re-arm inside the fire callback, but only on a premature ceiling clamp — detected as "nothing came due, yet entries remain" (the earliest due-time was past the ceiling, so the wake fired early and GC'd nothing). A normal wake (something came due) still leaves re-arming to the consumer, preserving the fire-once-per-schedule model and the existing "rescheduling cancels the prior timer" test.

Proof (red-first)

The existing "clamps a far-future due-time … and re-arms" test only asserted the first ceiling wake — which is why the bug shipped. Extended it to advance past the real due-time and assert the timer fires again (through the intermediate ceiling clamps) and finally GCs the entry:

× clamps a far-future due-time to the 32-bit timer ceiling and re-arms
  expected 1 to be greater than 1   // never re-armed without the fix

Scope

Internal (defer-timer.ts); no public surface. All defer + autoclose suites green; 100% coverage.

Gates

Typecheck ✅ · tests ✅ (3125 passed) · 100% coverage ✅ · lint ✅ · build ✅.

rfc-gate: exempt — no new public surface. The stability-snapshot delta is the internal defer-timer.ts fire-callback source text (an @internal module); the exported surface is unchanged.

Closes #1288

🤖 Generated with Claude Code

DeferTimer.schedule clamps a wait to the 32-bit setTimeout ceiling (~24.8
days) and its comment promised on_wake re-schedules for the remaining span,
but the drain consumer's on_wake only sets its armed flag and its arm-
triggered drain early-returns before the re-schedule (the stream is still
store-excluded). So a defer/autoclose-cooldown past the ceiling fired once
prematurely, then never re-armed — the precise wake was lost and the entry
leaked in the parked set.

Self-re-arm inside the fire callback, but only on a premature ceiling clamp
(nothing came due, yet entries remain). A normal wake still leaves re-arming
to the consumer, preserving the fire-once-per-schedule model (and the
existing "rescheduling cancels the prior timer" test).

The existing far-future test asserted only the first ceiling wake; extend it
to advance past the real due-time and prove the re-arm fires and GCs the
entry (red without the fix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Rotorsoft Rotorsoft added bug Something isn't working priority:medium Nice-to-have improvements area:workers Background workers labels Jul 19, 2026
@Rotorsoft Rotorsoft self-assigned this Jul 19, 2026
@Rotorsoft
Rotorsoft merged commit 7ea6d6a into master Jul 19, 2026
15 checks passed
@Rotorsoft
Rotorsoft deleted the act-1288-defertimer-rearm branch July 19, 2026 13:39
@github-project-automation github-project-automation Bot moved this from Todo to Done in Act Roadmap 2026 Jul 19, 2026
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version @rotorsoft/act-v1.23.10 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version @rotorsoft/act-tck-v1.27.13 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:workers Background workers bug Something isn't working priority:medium Nice-to-have improvements released

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

DeferTimer never re-arms past the 24.8-day setTimeout ceiling — long-horizon defers/cooldowns silently lose their precise wake

1 participant