Skip to content

feat: skip weekend digests and roll them into Monday - #54

Merged
alchemydc merged 2 commits into
mainfrom
feat/weekend-digest-skip
Aug 12, 2026
Merged

feat: skip weekend digests and roll them into Monday#54
alchemydc merged 2 commits into
mainfrom
feat/weekend-digest-skip

Conversation

@alchemydc

@alchemydc alchemydc commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Why

Community feedback: Saturday and Sunday digests go unread, and weekend activity is too thin to warrant its own post. This drops to five digests a week with no content loss — the weekend rolls into Monday.

How

Cloud Scheduler keeps firing daily (0 13 * * * UTC, unchanged). The application no-ops on Sat/Sun and extends Monday's lookback by 48h, covering Fri 13:00 → Mon 13:00 with no gap.

Keeping the rule in code rather than the cron expression is what makes the Monday extension possible at all: Cloud Scheduler cannot vary DIGEST_WINDOW_HOURS per day — it arrives as a repo Variable identical on every run. Cost is two Actions runs/week that exit in ~30s before contacting any API.

Day (13:00 UTC) Behaviour
Sat / Sun Logs Weekend (UTC) — skipping digest run, exits 0. No source, LLM, or Slack traffic.
Mon fetchMessages(24, 48) → 72h window, header shows a date range
Tue–Fri fetchMessages(24, 0) → unchanged

Notable decisions

  • getRunSchedule() (src/utils/time.ts) is the single place the weekday rule is stated — a pure, date-injected seam returning {skip, extraHours}.
  • SKIP_WEEKEND (default true) gates the whole policy. Setting it false restores plain daily behaviour: weekend runs happen and Monday loses its extension, so the two halves can never contradict each other.
  • One lookback window for every source. DISCOURSE_LOOKBACK_HOURS is removed. It let the forum fetch a different window than the digest header advertised — a pre-existing divergence that the weekend extension would have widened. All sources now take DIGEST_WINDOW_HOURS plus the Monday catch-up, so the advertised window and the fetched window are the same number by construction and cannot drift as sources are added. Source.fetchMessages(windowHours) keeps its original single-argument shape as a result.
  • The header now describes the window actually fetched. It previously rendered a calendar day against a rolling 13:00-to-13:00 window, misreporting by ~13h; a 72h Monday digest labelled with a single date would have made that visible. buildDigestBlocks' parameter shape is unchanged, so no existing format.test.ts call sites needed edits.
  • truncateMessages now warns when it drops messages. It discards the oldest, which on a Monday roll-up is Friday's content. Logging rather than raising MAX_INPUT_CHARS_PER_GROUP so the limit can be retuned from evidence.

Ops

The runbook's "digest missing" alert would have false-alarmed every weekend. §6/§7 now carry the carve-out (suppress the no-Slack-post half on Sat/Sun; the no-successful-run half still applies all seven days), and §9 gains a missed-Monday recovery recipe — that failure drops three days of content, not one.

No Cloud Scheduler change and no new repo Variable are required to deploy: an unset ${{ vars.SKIP_WEEKEND }} renders as "", which toBool maps to undefined, so the .default(true) inside the preprocess fires. Set the Variable only to turn the policy off.

Also fixes pre-existing runbook drift: it claimed the workflow keeps a schedule block as backup, which it does not.

DISCOURSE_LOOKBACK_HOURS is removed. If it is set as a repo Variable it becomes inert rather than failing — the Zod schema ignores unknown keys — so it can be deleted whenever convenient. Forum lookback now follows DIGEST_WINDOW_HOURS.

Testing

npm run build clean; 140 tests pass across 17 files.

  • test/unit/time.test.ts (new) — all 7 UTC weekdays × both flag values, plus explicit UTC-vs-local boundary cases.
  • test/unit/discourse_weekend_extension.test.ts (new) — Monday's 72h window reaches forum content a 24h window misses, with boundary cases either side.
  • digest_pipeline.test.ts — Sat/Sun make no calls; Monday passes 72 and titles the range correctly.
  • config.test.tsSKIP_WEEKEND default holds when unset and when empty-string (the GitHub Actions case).

Verified end-to-end against the compiled pipeline driven at fixed clocks, confirming the rendered Slack header:

=== Mon 2026-08-10T13:00:00Z ===
  HEADER : Community Digest — 2026-08-07 → 2026-08-10 (UTC)
  WINDOW : Time window: 2026-08-07 13:00–2026-08-10 13:00 UTC
  FETCH  : [72]

=== Tue 2026-08-11T13:00:00Z ===
  HEADER : Community Digest — 2026-08-11 (UTC)
  WINDOW : Time window: 2026-08-10 13:00–2026-08-11 13:00 UTC
  FETCH  : [24]

🤖 Generated with Claude Code

Community feedback: Saturday and Sunday digests go unread, and weekend
activity is too thin to warrant its own post.

Cloud Scheduler still fires daily; the application now no-ops on Sat/Sun
(UTC) and extends Monday's lookback by 48h so the two skipped runs are
covered with no gap. Keeping the rule in code rather than in the cron
expression is what makes the Monday extension possible at all —
Scheduler cannot vary DIGEST_WINDOW_HOURS per day.

- getRunSchedule() (src/utils/time.ts) is the single place the weekday
  rule is stated: returns {skip, extraHours} from a UTC weekday.
- SKIP_WEEKEND (default true) gates the whole policy. Setting it false
  restores plain daily behaviour: weekend runs happen AND Monday loses
  its extension, so the two halves can never contradict each other.
- extraHours is threaded through Source.fetchMessages as a separate
  argument rather than pre-added, so it stacks on top of
  DISCOURSE_LOOKBACK_HOURS instead of being swallowed by that override.
- The digest header now describes the window actually fetched. It
  previously rendered a calendar day against a rolling 13:00-to-13:00
  window, misreporting by ~13h; a 72h Monday digest labelled with a
  single date would have made that visible.
- truncateMessages warns when it drops messages. It discards the oldest,
  which on a Monday roll-up is Friday's content.
- The runbook's "digest missing" alert would have false-alarmed every
  weekend; §6/§7 now carry the carve-out, and §9 gains a missed-Monday
  recovery recipe (three days of content, not one).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Aug 11, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.11%. Comparing base (50ae1fd) to head (e5911a6).
⚠️ Report is 2 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #54      +/-   ##
==========================================
+ Coverage   80.95%   82.11%   +1.16%     
==========================================
  Files          12       12              
  Lines         483      492       +9     
  Branches      132      137       +5     
==========================================
+ Hits          391      404      +13     
+ Misses         31       28       -3     
+ Partials       61       60       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements weekday-only digest runs by skipping Sat/Sun (UTC) in-app and rolling weekend activity into Monday via an extra 48h lookback, while keeping Cloud Scheduler firing daily.

Changes:

  • Added getRunSchedule() + SKIP_WEEKEND config to skip weekend runs and extend Monday’s lookback by WEEKEND_EXTRA_HOURS (48).
  • Updated the pipeline, sources, and Slack header/window rendering to support a rolling time window and Monday date ranges.
  • Added/updated unit tests and operational documentation for the new weekday-only behavior.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/unit/time.test.ts New tests covering getRunSchedule() behavior across days and UTC boundary cases.
test/unit/discourse_weekend_extension.test.ts New tests ensuring Discourse lookback overrides stack with the weekend extension.
test/unit/digest_pipeline.test.ts Adds pipeline-level tests for weekend no-op and Monday extension propagation + titles.
test/unit/config.test.ts Extends config tests to cover SKIP_WEEKEND defaulting and parsing.
src/utils/time.ts Introduces WEEKEND_EXTRA_HOURS and getRunSchedule().
src/utils/format.ts Updates Slack “Time window” rendering to show actual fetched rolling timestamps.
src/services/llm/AiSdkProcessor.ts Adds a warning when truncation drops (oldest) messages.
src/services/discourse/DiscourseSource.ts Adds extraHours support and stacks it with DISCOURSE_LOOKBACK_HOURS override.
src/services/discord/DiscordSource.ts Adds extraHours support for extended lookback on Mondays.
src/DigestPipeline.ts Applies getRunSchedule() to skip weekends and extend Monday; updates context date titles and source calls.
src/core/interfaces.ts Extends Source.fetchMessages() contract to accept optional extraHours.
src/config/index.ts Adds SKIP_WEEKEND config with correct empty-string defaulting behavior.
README.md Updates product description to reflect weekday-only digests.
docs/production-runbook.md Updates ops/runbook for weekend behavior, alert suppression, and missed-Monday recovery steps.
AGENTS.md Documents the weekday-only digest policy and relevant code entry points.
.github/workflows/daily-digest.yml Passes SKIP_WEEKEND variable into workflow environment.
.env.example Documents SKIP_WEEKEND in the example environment file.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/utils/time.ts
Comment thread src/DigestPipeline.ts
Addresses review feedback on #54.

DISCOURSE_LOOKBACK_HOURS let the forum fetch a different window than the
one advertised in the digest header, so a larger override could surface
messages older than the header claimed to cover. Rather than teach the
header to compute max() across every source's private window, remove the
divergence: all sources now use DIGEST_WINDOW_HOURS (plus the Monday
weekend catch-up), so the advertised window and the fetched window are
the same number by construction.

With no per-source override left, the separate `extraHours` argument on
Source.fetchMessages had no remaining purpose — it existed only so the
weekend catch-up could stack on top of that override. The interface
reverts to fetchMessages(windowHours), and DigestPipeline passes the
total it already computed for the header.

Also corrects a wrong comment in getRunSchedule: 13:00 UTC is not the
same calendar day everywhere (UTC+13/+14 are already on the next day).
The reason to use getUTCDay() is to avoid depending on the host's local
timezone, not that timezones happen to agree.

Note for deploy: if DISCOURSE_LOOKBACK_HOURS is set as a repo Variable
it becomes inert rather than failing — the Zod schema ignores unknown
keys. It can be deleted at any time.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@alchemydc
alchemydc merged commit 75234b5 into main Aug 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants