Repository navigation
[2C-02]: Add scheduled_date column to notification_queue and populate on creation - #209
Merged
Merged
Conversation
…ar filtering (#201) Implements [2C-02]. ``scheduled_date`` is a calendar-day anchor on ``notification_queue`` denormalized from ``scheduled_at``: the companion app's recent view filters by device-local date without the server needing to know client TZ (Stream C v0.9 Q8 / E5). Migration 022 adds the column nullable, backfills existing rows from ``scheduled_at::date`` (Postgres uses session ``TimeZone``, BRAIN runs UTC), then alters NOT NULL and adds index ``ix_nq_scheduled_date``. ``NotificationCreate`` requires ``scheduled_date``; ``NotificationResponse`` echoes it; the list endpoint accepts ``?scheduled_date=YYYY-MM-DD`` for exact-day filtering. Internal callers in ``rule_evaluation`` derive the default from ``now.date()`` with the server-TZ assumption documented inline (a future SERVER_TZ from [2C-04] will swap that default if BRAIN ever runs non-UTC). Test coverage: schema-level 422 on missing/malformed ``scheduled_date``, response payload echo, ``?scheduled_date`` filter on the list endpoint, and Postgres-backed migration tests in ``tests/test_notifications_schema_022.py`` covering the ``scheduled_at::date`` backfill, the post-migration NOT NULL constraint, and ``ix_nq_scheduled_date`` presence.
7 of 8 tasks
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.
Verification
ruff check .— ✅ Pass (All checks passed!)pytest -v— ✅ Pass (1358 passed)tests/test_notifications_schema_022.py— 3 passed against migrated brain3-dev DB)Ran locally against develop HEAD at 5cd3b80 immediately before opening this PR.
Summary
Implements [2C-02]. Adds
scheduled_date(calendar-day anchor) tonotification_queueso the companion app's recent view can filter by device-local date without the server needing to know client TZ — resolves Stream C v0.9 Q8 / E5.scheduled_at(tz-aware DateTime) remains the source of truth for when the notification fires;scheduled_daterecords the calendar day the notification is for.Changes
alembic/versions/022_add_scheduled_date_to_notifications.py— new migration. Adds the column nullable, backfills existing rows fromscheduled_at::date(Postgres casts atimestamptztodateusing the session'sTimeZonesetting, which BRAIN runs in UTC — matches the in-app default), then alters NOT NULL and createsix_nq_scheduled_date. Two-step nullable→backfill→NOT NULL pattern keeps the upgrade safe whether the table is populated at upgrade time or not.app/models.py—NotificationQueue.scheduled_date: Mapped[date](NOT NULL) + matchingIndex("ix_nq_scheduled_date", "scheduled_date")in__table_args__.app/schemas/notifications.py—NotificationCreate.scheduled_date: date(required) andNotificationResponse.scheduled_date: date.NotificationUpdateleft untouched per spec (no allowance for changing the calendar-day anchor after creation).app/routers/notification.py— list endpoint acceptsscheduled_date: datequery param and filters with exact equality.app/services/rule_evaluation.py—_create_notificationnow populatesscheduled_date=now.date()with the server-TZ assumption documented inline. A futureSERVER_TZ(introduced by [2C-04]) will swap that default if BRAIN ever runs in a non-UTC timezone.NotificationQueue(...)directly updated to providescheduled_date. Three API helpers (test_notification_crud,test_notification_defaults,test_notification_respond,test_notification_expiry) now postscheduled_datein the create payload. New cases intest_notification_crud.py: missing-field 422, malformed-date 422, response payload echo,?scheduled_date=filter. New filetests/test_notifications_schema_022.pyruns the migration against a real Postgres (brain3-dev pattern fromtest_rules_postgres.py) and asserts thescheduled_at::datebackfill, the post-migration NOT NULL constraint, and the index presence.How to Verify
git checkout feat/2C-02-scheduled-date-columnpytest -v— 1358 pass; the three Postgres-backed migration tests intests/test_notifications_schema_022.pyexercise the backfill end-to-end.pytest -v— schema-022 tests skip with the same reason as the existing Postgres-backed suite, the rest still pass.ruff check .— clean.POST /api/notifications/withoutscheduled_date→ 422; with validscheduled_date→ 201 and the response body includes the field;GET /api/notifications/?scheduled_date=2026-04-15returns only same-day rows.Deviations
021_add_scheduled_date_to_notifications.pybecause it was authored against a tree where 020 was the head. Between spec freeze and this dispatch, [2C-26] shipped021_add_routine_completions_unique_constraint.py(revision21a1b2c3d4e5). I bumped this ticket's migration to022_add_scheduled_date_to_notifications.py(revision22a1b2c3d4e5,down_revision='21a1b2c3d4e5') and the new test file totests/test_notifications_schema_022.py. Spec intent (next sequential after current head) is preserved.D:\_DEVELOPMENT\CLAUDE.mdis older than BRAIN org CLAUDE.md v5 (April 27, 2026) — it lacks the inheritance-and-source-of-truth section. BRAIN won for this session per directive4ea28266(CLAUDE.md is PO-controlled). Flagging only — not modifying the file.Test Results
Highlights of new coverage:
tests/test_notification_crud.py::TestCreateNotification::test_create_missing_scheduled_date_rejected— 422tests/test_notification_crud.py::TestCreateNotification::test_create_response_includes_scheduled_date— payload echotests/test_notification_crud.py::TestCreateNotification::test_create_invalid_scheduled_date_format_rejected— 422 on malformed datetests/test_notification_crud.py::TestListNotifications::test_filter_by_scheduled_date— exact-day filtertests/test_notifications_schema_022.py::TestMigration022Backfill::test_backfill_populates_scheduled_date_from_scheduled_at— Postgres backfilltests/test_notifications_schema_022.py::TestMigration022Backfill::test_post_migration_insert_without_scheduled_date_fails— NOT NULL enforcedtests/test_notifications_schema_022.py::TestMigration022Backfill::test_index_on_scheduled_date_exists— index presentAcceptance Checklist
test_backfill_populates_scheduled_date_from_scheduled_atagainst brain3-dev).POST /api/notifications/withoutscheduled_date→ 422 with a clear validation error.POST /api/notifications/with a validscheduled_date→ 201, response body includes the field.scheduled_datein the same commit).GET /api/notifications/?scheduled_date=YYYY-MM-DDreturns only notifications with that calendar-date match.Closes #201