-
released this
2026-04-29 16:04:58 -04:00 | 287 commits to main since this releaseCloses the 4/29 dentist-appointment investigation. Two complementary structural fixes plus the held-back EventSlideOver UX refactor.
Event-store data integrity
#160— Duration replaces end_dt at the storage layer. Schema migration 0043 addsduration_minutes(with>= 0CHECK constraint) and dropsend_dt. Wire format unchanged —end_dtis now a derived@property. End-before-start is structurally inexpressible. The corrupt prod row that triggered this work backfills toduration_minutes=NULLautomatically.Behavioral upgrade: moving an event's start now slides the effective end forward (preserving duration), instead of corrupting or hard-rejecting.
#161— Tool layer disambiguates multi-match. Whenupdate_eventordelete_eventget a query that matches 2+ events, the tool returnssuccess: falsewith acandidatesarray. The model picks one by passingevent_idon the next call. Pre-fix: both tools silently tookmatches[0], which is exactly how the dentist event got applied to the wrong row.Calendar UX
EventSlideOver redesigned as a centered modal. Auto-save on close (X / Esc / backdrop click / Enter in form). Trash icon in the header (edit mode only). Invalid form in edit mode → toast + discard; in create mode → silent discard. Removes the right-edge floor band where the destructive Delete button was visually invisible.
Reverted in-flight
94b169f(A+B hotfix) is reverted byb7e7073— superseded by#160. The hotfix made bad data filterable;#160makes it inexpressible.
46 calendar/events tests pass. Ruff clean. Schema migration runs automatically on container restart. Tag push triggers the build.
Downloads