Skip to content

Today views: a recurring event is on Today, the kitchen display, the kids' day and the assistant's context every week - #922

Merged
NewWorldVenture merged 4 commits into
mainfrom
claude/today-views-see-series-20261003
Oct 4, 2026
Merged

NewWorldVenture merged 4 commits into
mainfrom
claude/today-views-see-series-20261003

Conversation

@NewWorldVenture

Copy link
Copy Markdown
Owner

Stacked on #921 for readCalendarOccurrences. No migration. Retarget to main when #921 lands.

What was wrong

After the briefs (#921), the same first-occurrence-only read of calendar_events was still in seven places:

  • the home page's Today (with its "N events today" badge) and Coming Up;
  • the kids' day;
  • the kitchen display: today, the fortnight ahead, and the month's marked days;
  • the assistant's "what's coming up" context (/api/ai/chat) and the chef's week (/api/ai/chef);
  • the digital twin's six-month load for one member, in both of its actions.

Each filtered starts_at by the window, so a weekly practice was on those surfaces the week it was created and never again. The kitchen display, which hangs on the wall precisely to show what is on today, showed the practice once.

Change

  • All seven reads go through readCalendarOccurrences, with the columns they used before.
  • The shared read (lib/calendar/occurrences.ts) gains what they needed: count, every occurrence in the window before the limit, so the home badge counts the day while the list is cut to eight; assigneeId, one member's events, for the twin; and singlesFilter, so the kitchen display keeps its own overlap rule for one-off rows (an overnight sleepover that started yesterday and is still on shows today) while a series is expanded from its rule. The two reads are now issued together and awaited together, which also fixes the order of database calls whatever fails. displayCalendarBounds (lib/display/calendar.ts) turns a display window into the read's bounds.
  • The assistant's context, previously unbounded ahead, is bounded to a month, which is as far as "what's coming up" reaches.

Tests

  • tests/today-views-see-every-week-of-a-series.test.ts (10): the count before the limit; one member's load with series included and another member's untouched; the display's overlap rule kept and this week's occurrence of every series added, the month's marks counted (30 bins, 5 Wednesdays of soccer, 4 of piano, 2 one-offs); the assistant's next twelve, bounded, with today's all-day item first and this afternoon's practice the first timed thing; a source pin that the six files read through the helper with no bare calendar_events read left.
  • tests/display-page-calendar.test.ts gains a series case through the real page: today's occurrence under events, next week's under upcoming, every Saturday of the month marked, all four loads ok. Its boundary fake learns the two-reads-per-window rhythm (one label per two consecutive calendar calls), which is what lets its "events unavailable, upcoming unavailable" cases keep injecting failures into the right read.
  • The briefs test's refusal stub matches the read's chain.

Mutation controls (each reverted): count after the limit → 1 fails; assignee ignored → 1 fails; the overlap filter ignored → 3 fail; the display's today read restored to the bare query → 5 fail (the series case and the source pin among them). 20 related suites 605/605 (display page and calendar, kids read boundary, family-day guards, server-rendered-time guards, widget boundary, AI action and provider body boundaries, catalogue keys, observability coverage, write ratchets, briefing schema and localization). tsc --noEmit and ESLint clean.

Not done

🤖 Generated with Claude Code

https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K


Generated by Claude Code

claude added 2 commits October 3, 2026 19:11
… week it was created

calendar_events stores a series as one row whose starts_at is its first
occurrence. The daily brief, the weekly brief, the weekly digest email
and the pushed morning brief all read "today's" or "this week's" events
by filtering that column by the window (briefingCalendarWindow's own
docstring: "selects start dates only, without expanding … recurrence"),
so the weekly soccer practice a family created in August was in the
brief that week and in no brief after. The calendar page expands series;
the briefs did not.

lib/calendar/occurrences.ts: readCalendarOccurrences is the read the
four surfaces now share. One-off rows by the window filter as before
(timed rows by family-local instants, all-day rows by stored date),
series excluded there and read whole instead (started by the window's
end, not ended before its start, one row past a 2000 ceiling is a failed
read), expanded with the calendar page's expander — timed series in the
family's zone, all-day series by date — merged, sorted, and the caller's
limit applied last, so eight slots of "coming up" are the eight nearest
things. Both lists are filtered in code as well as in the query, so a
row answered out of place is counted once. The caller names its columns
as a typed list; the recurrence columns ride along.

lib/briefing/calendar-window.ts exports the bounds the filter is built
from (briefingCalendarBounds), a variant for a window held as instants
(instantCalendarBounds, inclusive end as the weekly windows are built)
and the filter itself; the filter string is unchanged. The daily
briefing, the weekly briefing, the weekly digest cron and
lib/briefing/deliver.ts call the shared read.

tests/the-brief-sees-every-week-of-a-series.test.ts (12): today holds
the one-offs and this week's occurrence of every series once each in
time order, with the occurrence's own instants; the control shows the
old filter alone has neither the practice nor the daily all-day item;
limit after the merge; the coming week (seven days of a daily series,
next week's practices, a series starting then, not an ended one); a
timed series keeps its local hour across the clock change; an instant
window reads the same way; a failed read is the error it was; the daily
route end to end on its deterministic path lists the practice at
3:00 PM; and a source pin that the four surfaces read through the
helper and no bare calendar_events read remains in them. The weekly
digest test's hand-rolled fake gains the two chain methods the read
uses. Controls: no series read fails 6; masters counted twice fails 3;
limit ignored fails 1. 28 related suites 663/663; tsc, eslint clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
…kids' day and the assistant's context every week

After the briefs, the same first-occurrence-only read was still in the
home page's Today and Coming Up, the kids' day, the kitchen display
(today, the fortnight, the month's marks), the assistant's "what's
coming up" context, the chef's week and the digital twin's six-month
load (two actions). Each read calendar_events by starts_at alone, so a
weekly practice was on those surfaces the week it was created and never
again. All of them now read through readCalendarOccurrences.

The shared read gains what they needed: `count` (every occurrence
before the limit, for the home badge beside a list cut to eight),
`assigneeId` (one member's load, for the twin) and `singlesFilter`
(the kitchen display reads one-offs that OVERLAP the window, so an
overnight sleepover still shows; a series is expanded from its rule).
The two reads are now issued together and awaited together, which also
makes the order of database calls fixed whatever fails. The assistant's
context, previously unbounded ahead, is bounded to a month, which is as
far as "what's coming up" reaches. displayCalendarBounds turns a display
window into the read's bounds.

tests/today-views-see-every-week-of-a-series.test.ts (10): count before
limit; one member's load, series included, another member's untouched;
the display's overlap rule kept and this week's occurrence of every
series added, the month's marks counted; the assistant's next twelve,
bounded, all-day today first; and a source pin that the six files read
through the helper with no bare calendar_events read left. The kitchen
page suite gains a series case (today's occurrence, next week's under
upcoming, every Saturday marked) and its fake learns the two-reads-per-
window rhythm; the briefs test's refusal stub matches the read's chain.
Controls: count after the limit fails 1; assignee ignored fails 1; the
overlap filter ignored fails 3; the display's today read as it was fails
5. 20 related suites 605/605; tsc, eslint clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
@vercel

vercel Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
bubaly Ignored Ignored Oct 4, 2026 7:22am UTC

Request Review

… requires

CI on the today-views branch failed one case: "counts the full Home day
beyond its eight visible event rows". Its ten seeded rows carried no
`all_day`. The column is NOT NULL (0002), and the series-aware read Home
now uses (lib/calendar/occurrences.ts) selects timed rows and all-day rows
by different bounds, so a row that is neither falls on no window and the
count read as zero. The seeds now say `all_day: false`, as every real row
does; the case's own assertion (count 10 past the eight visible rows,
another family excluded) is unchanged and passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
… squash-merged, so the stack re-roots on main

#921 (briefs see every week of a series) was rebased onto main and merged as
657d70f; this branch still carried #921's original commits, so git saw
lib/calendar/occurrences.ts and its test as added on both sides with no common
ancestor. Resolved as a three-way merge against the tip this branch was built
on (fd7901a): main's final #921 (the paged series read) plus this unit's
extensions (count, OccurrencesOptions, the assignee scope, the overlap filter,
the two reads issued together). Typecheck clean; 743 tests across the brief,
today, kitchen and whole-table suites pass. The PR now targets main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
@NewWorldVenture
NewWorldVenture marked this pull request as ready for review October 4, 2026 09:08
@NewWorldVenture
NewWorldVenture merged commit 933236e into main Oct 4, 2026
7 checks passed
NewWorldVenture pushed a commit that referenced this pull request Oct 4, 2026
…eries-20261003

#922 (the base of this branch) was rebased and squashed onto main as
933236e. lib/calendar/occurrences.ts conflicted only because the two
histories carry the same change twice; main's version is byte-identical to
the old base tip, so this branch's own additions to the file are kept as
they were.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture pushed a commit that referenced this pull request Oct 4, 2026
…-practice-every-week-20261003

Carries main (933236e, #922 squashed) down the series stack through the
re-rooted planner branch. No conflicts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture pushed a commit that referenced this pull request Oct 4, 2026
…/every-server-surface-sees-series-20261003

Carries main (933236e, #922 squashed) down the series stack. No conflicts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture pushed a commit that referenced this pull request Oct 4, 2026
…claude/dashboard-pages-see-series-20261003

Carries main (933236e, #922 squashed) down the series stack. No conflicts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture pushed a commit that referenced this pull request Oct 4, 2026
…/client-modules-see-series-20261003

Carries main (933236e, #922 squashed) down the series stack. No conflicts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
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.

2 participants