; persist/upcast — event schema evolution. An append-only log keeps events ; forever, so old events have old shapes. Rather than migrate stored data (you ; can't rewrite history) or branch every projection on version, register an ; upcaster per event type: a pure (event -> event) that lifts an old event to ; the current shape. Reads pass through the registry so projections see ONE ; shape. The registry is an immutable dict the consumer threads (no global ; mutable state). Requires: lib/persist/event.sx, lib/persist/log.sx. (define persist/upcasters (fn () {})) (define persist/register-upcaster (fn (reg type fn) (assoc reg type fn))) ; apply the registered upcaster for an event's type, or pass it through unchanged (define persist/upcast (fn (reg e) (let ((f (get reg (persist/event-type e)))) (if f (f e) e)))) ; read a stream with every event lifted to current shape (define persist/read-upcast (fn (b stream reg) (map (fn (e) (persist/upcast reg e)) (persist/read b stream)))) ; project over upcasted events — projections never see a legacy shape (define persist/project-upcast (fn (b stream reg step seed) (reduce step seed (persist/read-upcast b stream reg)))) ; helper: upcast an event's :data by merging in/overriding fields, keeping the ; record's stream/seq/type/at. Common upcaster body. (define persist/upcast-data (fn (e new-data) (persist/event (persist/event-stream e) (persist/event-seq e) (persist/event-type e) (persist/event-at e) (merge (persist/event-data e) new-data))))