V185: activities can be permanent, and are ordered to the microsecond; posts remember the zone they were scheduled in.
Why
A stored instant does not say which regime wrote it. When the time_zone
setting moved from an integer offset to an IANA id (2.13.9) and five
modules turned out to have added that value to other instants, the rows
they had written could not be repaired, because nothing recorded WHEN the
setting changed or what it was before: phoenix_kit_settings.date_updated
holds the last change only, and no settings writer logged to the activity
feed — which prunes after activity_retention_days anyway. The question
"what was this setting at that instant?" had no answer.
The activity feed is the right home for that answer — it already holds who did what to which resource, with a before/after convention in its metadata and an admin page — once two things hold:
permanent(boolean NOT NULL DEFAULT false): an entry the pruner never deletes. Any module may keep an entry this way; settings changes are the first.inserted_atto the microsecond (timestamp(0)→timestamp): "what was the value at that instant" walks a resource's entries by time, and two changes inside one second must not read as simultaneous. Widening the precision rewrites no rows.
And the posts column
phoenix_kit_posts.time_zone (varchar(64), nullable) is the same
lesson applied to the one core-owned table that stores a typed wall clock:
the posts module reads scheduled_at in the editor's zone, and a row that
carries that zone can be re-resolved on its own. Rows written before this
hold nil.
Rolling back drops the flag (permanent entries become prunable) and the
posts column. It leaves inserted_at wide: narrowing it back would
rewrite and round every row under an exclusive lock, and the previous
code reads a microsecond value fine (Ecto truncates on load).