Skip to content

fix(agent-memory-sync): reject cron step<=0 to stop scheduler infinite-loop hang (+ coverage)#61

Merged
LanNguyenSi merged 3 commits into
masterfrom
fix/scheduler-step-zero-infinite-loop
Jul 1, 2026
Merged

fix(agent-memory-sync): reject cron step<=0 to stop scheduler infinite-loop hang (+ coverage)#61
LanNguyenSi merged 3 commits into
masterfrom
fix/scheduler-step-zero-infinite-loop

Conversation

@LanNguyenSi

Copy link
Copy Markdown
Owner

What

Fixes a pre-existing infinite-loop hang in the agent-memory-sync cron scheduler, and closes two residual test-coverage gaps. Follow-up to the coverage PR #60.

The bug

parsePart validated a cron step token against the field range via parseInteger(stepToken, min, max). For min=0 fields (minute, hour, dayOfWeek), step=0 was accepted, and fillRange(result, min, max, 0) then looped forever (cursor += 0). A typo'd cron string like */0 * * * * hung the sync daemon unbounded. Confirmed: validateCronExpression('*/0 * * * *') timed out at 3s (exit 124).

The fix

A new parseStep validates the step as an integer >= 1, independent of the field's min/max (per the task spec). There is no upper bound: a step larger than the range collapses to the start value in a single terminating fillRange iteration.

Tests

  • agent-memory-sync: */0 now throws instead of hanging, the range-independent */90 is valid, and the unsupported lone-value 5/2 form is pinned as throwing. 49 tests pass.
  • memory-router: asserts the 5000ms default embed timeout is wired into AbortSignal.timeout and that its signal reaches fetch, plus the explicit-override branch. 233 tests pass.
  • memory-digest-cli: real generate-action integration tests (markdown write, json write, stdout print, catch to process.exit(1)) that drive the actual action instead of a spy stub; tightened a tautological description assertion. 24 tests pass.

All three package coverage gates pass. Reviewed adversarially: every mutation was caught.

Follow-up

The lone-value step form a/n (e.g. 5/2) throws with a confusing 'undefined ... outside range' message, where standard cron reads it as a-max/n. Tracked as a separate task.

Refs: agent-memory task 124c89e0

nguyen-si-pp and others added 3 commits July 1, 2026 05:24
parsePart validated a step token against the field range via
parseInteger(stepToken, min, max). For fields with min=0
(minute/hour/dayOfWeek) step=0 was accepted, and fillRange(result, min,
max, 0) then looped forever (cursor += 0) — a typo'd operator cron
string like '*/0 * * * *' hung the sync daemon unbounded.

Validate the step independently as an integer >= 1 (new parseStep), with
no upper bound: a step larger than the range simply collapses to the
start value in a single terminating fillRange iteration. Adds tests for
the rejected '*/0', the now-valid range-independent '*/90', and pins the
existing throw for the unsupported lone-value 'a/n' step form.

Refs: agent-memory task 124c89e0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The embed-provider suite proved an abort throws but never that the
DEFAULT_TIMEOUT_MS (5000) is the value handed to AbortSignal.timeout and
that its signal reaches fetch. Spy over the real AbortSignal.timeout
(call-through) to pin the 5000ms default and the explicit-override
branch of `opts.timeoutMs ?? DEFAULT_TIMEOUT_MS`.

Refs: agent-memory task 124c89e0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generate suite replaced the action with a spy, so the real body
(scan → extract → generate → format → write/print + catch→exit) had ~0%
coverage. Add integration tests driving the real registerGenerateCommand
action against today-dated temp-dir fixtures: markdown --output write,
--json --output write (also parsing non-default --days/--max), stdout
print when --output is omitted, and the catch/process.exit(1) branch via
an unwritable --output path. Stubs console.log/error and process.exit
with save/restore. Tightens the tautological description assertion to
the exact string.

Refs: agent-memory task 124c89e0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@LanNguyenSi LanNguyenSi added review:tests-pass merge-approval gate prerequisite review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite labels Jul 1, 2026
@LanNguyenSi LanNguyenSi merged commit f99d0af into master Jul 1, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:checklist-complete merge-approval gate prerequisite review:comments-resolved merge-approval gate prerequisite review:evidence-logged merge-approval gate prerequisite review:scope-matches-task merge-approval gate prerequisite review:tests-pass merge-approval gate prerequisite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants