Skip to content

fix(memory): guard prune_history against negative keep_days - #8569

Closed
mbajaj92 wants to merge 1 commit into
kirodotdev:mainfrom
mbajaj92:fix/8245-negative-keep-days
Closed

fix(memory): guard prune_history against negative keep_days#8569
mbajaj92 wants to merge 1 commit into
kirodotdev:mainfrom
mbajaj92:fix/8245-negative-keep-days

Conversation

@mbajaj92

@mbajaj92 mbajaj92 commented Sep 4, 2026

Copy link
Copy Markdown

Problem / Motivation

MemoryStore.prune_history() trusts its keep_days argument without validation. A negative history_max_days in config.json — caused by a hand edit, bad import, or file corruption — makes the heartbeat wipe the entire daily history on every tick.

When keep_days is negative, timedelta(days=keep_days) computes a future date, so every existing history file appears "older than the cutoff" and gets unlinked.

Why it matters

Silent, unrecoverable data loss. A single corrupted config value causes the periodic heartbeat to delete all daily history files with only an INFO log. The user sees empty memory with no warning.

The dashboard settings path already clamps to min 7 (dashboard/handlers/memory.py); this fix closes the same gap on the file-config path (heartbeat.pyprune_history).

What changed (motivation → approach → change)

Negative keep_days → future cutoff date → all files appear old → everything deleted.

A negative value can never be intentional (you cannot keep a negative number of days of history). Fall back to the default retention of 365 days and emit a WARNING log so the operator knows their config value is invalid — instead of silently deleting all history.

Zero retains its current meaning: drop everything before today.

Tests

Added TestPruneHistory class in test/test_memory.py with three tests:

  • test_negative_keep_days_does_not_delete_recent_fileskeep_days=-1 falls back to 365; a 10-day-old file is kept
  • test_zero_keep_days_drops_files_older_than_today — zero keeps its existing semantics; yesterday's file is deleted
  • test_positive_keep_days_deletes_old_files — normal path still works; only files older than the threshold are deleted

Manual verification

N/A — unit coverage sufficient. The code path is heartbeat._beat() → prune_history(keep_days=config.memory.history_max_days); the guard fires on any negative integer regardless of how it arrives.

Related Issues

Fixes #8245

Pattern harvest

Rule candidate: lint
Pattern: integer config value passed directly to a time-delta calculation without a lower-bound guard

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

A negative history_max_days in config.json (hand edit, bad import, or
corruption) caused prune_history() to compute a cutoff in the future,
making every history file appear 'old' and deleting the entire daily
history silently.

Negative keep_days can never be intentional. Fall back to the default
retention of 365 days and emit a WARNING instead of deleting all files.
Zero retains its current meaning (drop everything before today).

The dashboard path already clamps to min 7; this fix closes the same
gap on the file-config path that goes through heartbeat.py.

Fixes kirodotdev#8245
@mbajaj92
mbajaj92 requested a review from a team as a code owner September 4, 2026 22:01
@mbajaj92
mbajaj92 requested a review from iamwhatever September 4, 2026 22:01
@mbajaj92

mbajaj92 commented Sep 4, 2026

Copy link
Copy Markdown
Author

Closing as a duplicate — #8246 merged the same fix 3 hours before this PR was opened.

@mbajaj92 mbajaj92 closed this Sep 4, 2026
@mbajaj92
mbajaj92 deleted the fix/8245-negative-keep-days branch September 4, 2026 22:04
@github-actions github-actions Bot added the fork Pull request from a fork (external contributor) label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: negative history_max_days makes the heartbeat wipe all daily memory history

1 participant