Skip to main content

max / goingson

Drop the one-time routine classification script It has run against the live database and has nothing left to do. Keeping it invites a re-run: the Denver offset is hardcoded as -6 hours, correct for MDT and wrong for half the year, and it carries a specific event's external_id. That is fine for a script applied once under supervision and a hazard for one sitting in the tree. What it did, so the resulting data state is explained rather than mysterious: fourteen personal routines became `relative`, and Stream became `local` anchored to America/Denver. Stream is anchored rather than absolute because it is a commitment to an audience on Denver time, and a fixed UTC instant would drift an hour against Denver's wall clock at each DST boundary, moving the stream relative to the schedule around it twice a year. Reclassifying again means writing the statement for the case at hand, which is the honest amount of work for a one-off edit to personal data.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-27 17:34 UTC
Signed with PGP, not checked
Commit: facab7edfb808e4eeb78de3ed1956f7bccfb4f8d
Parent: dd5c6d7
1 file changed, +0 insertions, -45 deletions
@@ -1,45 +1,0 @@
1 - -- One-time reclassification of personal routines from `absolute` to `relative`.
2 - --
3 - -- Migration 063 deliberately lands every existing row as `absolute`, because
4 - -- that is how it was already being treated and a migration must not guess. This
5 - -- script is the deliberate follow-up for a calendar whose events are personal
6 - -- routines: wake, swim, gym, errands, meal prep. Those should follow the user,
7 - -- so that a month spent in another zone still has breakfast at 06:00.
8 - --
9 - -- RUN AFTER the app has applied migration 063 (open GoingsOn once). Applying the
10 - -- DDL by hand instead would leave sqlx's `_sqlx_migrations` table thinking 063
11 - -- is still pending, and the next launch would fail on a duplicate column.
12 - --
13 - -- Not idempotent in spirit but safe to re-run: the WHERE clause excludes rows
14 - -- already converted, and the civil times are derived from the stored UTC in the
15 - -- zone the events were authored in.
16 - --
17 - -- sqlite3 ~/.local/share/com.goingson.app/goingson.db \
18 - -- ".param set :tz 'America/Denver'" \
19 - -- ".read scripts/classify_routines_relative.sql"
20 - --
21 - -- Verify first against a copy. `SELECT` the result before committing to it.
22 -
23 - -- SQLite has no IANA database, so the civil time cannot be derived here from a
24 - -- zone name. The events were authored in Denver, which was UTC-6 (MDT) for all
25 - -- of them, so the offset is applied literally and the assumption is stated
26 - -- rather than hidden. An event authored during MST (UTC-7) would need -7 hours;
27 - -- none of the current rows are.
28 - UPDATE events
29 - SET tz_kind = 'relative',
30 - timezone = NULL,
31 - start_local = strftime('%Y-%m-%d %H:%M:%S', start_time, '-6 hours'),
32 - end_local = CASE
33 - WHEN end_time IS NULL THEN NULL
34 - ELSE strftime('%Y-%m-%d %H:%M:%S', end_time, '-6 hours')
35 - END
36 - -- Scoped by provenance rather than by "not imported". The routines carry an
37 - -- `external_source` of routine-weekday / routine-weekend / routine-exercise:
38 - -- self-authored rows stamped with a seed marker, not a foreign calendar. A
39 - -- blanket `external_source IS NULL` guard silently matches nothing here, which
40 - -- is exactly the sort of no-op that reads as success.
41 - WHERE tz_kind = 'absolute'
42 - AND external_source IN ('routine-weekday', 'routine-weekend', 'routine-exercise')
43 - AND is_read_only = 0 -- never touch a row a foreign calendar owns
44 - AND linked_task_id IS NULL -- nor a time block, which mirrors a task's schedule
45 - AND (recurrence != 'None' OR recurrence_rule IS NOT NULL);