Reject in-progress current year in web digest generation - #3565
Merged
Freika merged 1 commit intoSep 9, 2026
Merged
Conversation
Freika
deleted the
detail/bug-fix/reject-in-progress-current-year-in-web-digest-gene-9d64b8
branch
September 9, 2026 18:50
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.
Detail bug report: View on Detail
Bug
The web
Users::DigestsController#createaction gates year-end digest generation on avalid_year?helper whose upper-bound check used a strict>comparison, soyear == Time.current.yearwas accepted and aUsers::Digests::Yearly::CalculatingJobwas enqueued for the still-in-progress year. The API controller (Api::V1::DigestsController#valid_year?) already used>=and rejected the current year, and the rest of the system — the yearly auto-scheduler (SchedulingJobtargets1.year.ago.year) and both controllers' dropdown builders (available_years_for_generationsubtracts[Time.current.year]) — treats year-end digests as valid only for complete, past years. The webvalid_year?was the lone outlier.Impact: a signed-in user making an out-of-band
POST /users/digests?year=<current_year>(the standard dropdown never offers the current year) could trigger generation of a partial-year digest.CalculatingJobpersists aUsers::Digestrow and chainsEmailSendingJob, which delivers a partial "Year in Review" email unlessdigest.distance.to_i.zero?. The persisted row also temporarily hides that year from the generation dropdown until repaired.Fix
One-character change in
app/controllers/users/digests_controller.rb:year > Time.current.year→year >= Time.current.year, matchingApi::V1::DigestsController#valid_year?. The web route now rejects the in-progress current year with the existingInvalid year selectedalert and enqueues no job, aligning the web controller with the API, the dropdown builder, and the scheduling job. No new routes, migrations, i18n keys, or public API surface.Testing
spec/regressions/digests_current_year_boundary_spec.rb— freezes time to mid-2026, creates aStatfor the current year (soscoped_stats.exists?is true and only the upper-bound operator can reject), and asserts both web and API reject the current year (no job enqueued; web alert / API 422) while still accepting a past year (job enqueued; web notice / API 202). The spec is load-bearing: reverting the operator back to>makes the web example fail withexpected not to enqueue at least 1 jobs, but enqueued 1.CalculateYearservice spec pass with no regressions. RuboCop on the modified files andrails zeitwerk:checkboth pass.POST /digests?year=2026returned 303 with theInvalid year selectedflash, persisted no digest, and enqueued no job;POST /digests?year=2025returned 303 with the "is being generated" notice, enqueuedCalculatingJob, which chainedEmailSendingJoband persisted a 2025 digest (distance 0 → email suppressed); the/digestsdropdown omitted the current year;POST /api/v1/digestswith the current year returned 422{"error":"Invalid year"};DELETE /digests/2025destroyed the digest. The dev DB and Redis were cleaned afterward.Automatic Fixes PRs can be configured here.