feat(memory-engine): add off-peak consolidation windows - #3233
Open
xiaoxiaoHe-E wants to merge 2 commits into
Open
feat(memory-engine): add off-peak consolidation windows#3233xiaoxiaoHe-E wants to merge 2 commits into
xiaoxiaoHe-E wants to merge 2 commits into
Conversation
…#2762) Restrict the consolidation background job (Hindsight's most LLM-heavy operation) to a configurable daily off-peak window, e.g. 01:00-06:00. Tasks that land outside the window are deferred — held as pending with next_retry_at set to the next window open — instead of running during peak hours. The backlog drains automatically when the window reopens (claim SQL "next_retry_at <= NOW()"). - New static config trio: HINDSIGHT_API_CONSOLIDATION_WINDOW_START/END/TZ. START > END means a cross-midnight window; START == END is treated as always-open. Unset = always-on (previous behaviour). - Window arithmetic lives in engine/consolidation_window.py as a pure, fully deterministic function (normal, cross-midnight, DST-aware). - _handle_consolidation defers via DeferOperation while the window is closed; on the sync task backend (tests/CLI/embedded, no worker queue to re-claim the task) it logs and runs anyway instead of 500-ing the HTTP caller or stranding a pending op. - Wire the previously-defined-but-never-called validate_consolidate extension hook into the same deferral path. - Docs, .env.example and the embed env template updated; 21 unit + integration tests added.
…e-io#2762) Add deterministic unit tests for _parse_consolidation_window and _parse_consolidation_window_boundary: HH:MM validation (valid, missing, malformed), the START/END-must-be-paired rule, the START==END degenerate case, and the timezone fallback (invalid/empty -> UTC). These are the operator-facing entry point of the off-peak window config and previously had no direct coverage — the gate tests bypass parsing by mutating _get_raw_config() fields directly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #2762 — restrict the consolidation background job (Hindsight's most LLM-heavy operation) to a configurable daily off-peak window (e.g.
01:00–06:00), instead of firing whenever facts become eligible.Tasks that land outside the window are deferred, not failed: the worker holds them as
pendingwithnext_retry_atset to the next window open, and the backlog drains automatically when the window reopens (claim SQLnext_retry_at <= NOW()).Changes
config.py):HINDSIGHT_API_CONSOLIDATION_WINDOW_START/HINDSIGHT_API_CONSOLIDATION_WINDOW_END—HH:MM(24h) daily window boundaries; must be set together.START > END= cross-midnight window (e.g.22:00–06:00);START == END= always-open. Unset = always-on (previous behaviour).HINDSIGHT_API_CONSOLIDATION_WINDOW_TZ— IANA timezone the boundaries are evaluated in; unknown names fall back toUTCwith a warning.engine/consolidation_window.py(new) — pure, deterministicnext_window_open()schedule arithmetic (normal / cross-midnight / DST-aware), unit-tested._handle_consolidationgate — defers via the existingDeferOperationmechanism (noretry_countbump, noerror_message) while the window is closed.validate_consolidateextension hook into the same deferral path — it was defined on the validator interface but never called for consolidation. A rejection is now a deferral (retry-backoff), not an HTTP 403.SyncTaskBackend(tests / CLI / embedded single-process) there is no worker queue to re-claim a deferred task, so raisingDeferOperationwould 500 the HTTP caller and strand apendingop that blocksbanks_needing_consolidation()from re-submitting the bank. There it logs and runs now (window closed) / skips (hook rejection) instead.Notes
run_consolidation()(explicit user trigger) is intentionally not gated by the window — the window applies to the async background job.replace(); on DST spring-forward/fall-back transition days the boundary can shift by one hour (window times are typically in the early morning).Testing
next_window_open) + env parsing (_parse_consolidation_window*).next_retry_at= next window open), reconcile non-resubmission, extension rejection deferral, sync-backend run-now/skip behaviour.ruff,ty, and the repo pre-commit hooks (lint.sh,generate-docs-skill.sh,check-unused.sh) all pass.Closes #2762