;; lib/host/ledger.sx — the strangler migration ledger. A catalogue of every ;; rose-ash HTTP endpoint with its Quart original and its current host status, so ;; the cut-over from Quart to the SX host is tracked endpoint-by-endpoint rather ;; than big-bang. Status is one of: ;; :native — born on the host, has no Quart original (e.g. /health probe) ;; :migrated — moved off Quart, now served by an SX handler ;; :proxied — still on Quart; the host forwards until cut over ;; Coverage (how far the strangler has progressed = how much is OFF Quart) is ;; computed from the catalogue. Pure data + queries — no IO, fully conformable. ;; ── entry constructor ─────────────────────────────────────────────── ;; quart is a "service:handler" ref string (nil for :native endpoints); handler ;; is the SX handler name serving it (nil while still :proxied). (define host/ledger-entry (fn (domain method path quart status handler) {:domain domain :method method :path path :quart quart :status status :handler handler})) ;; ── the catalogue ─────────────────────────────────────────────────── ;; Reflects the live host: feed reads+writes migrated, /health native, the ;; relations container endpoints migrated onto lib/relations (reads get-children/ ;; get-parents + writes attach-child/detach-child — see lib/host/relations.sx). ;; The TYPED relations actions (relate/unrelate/can-relate) stay proxied: they ;; carry registry + cardinality validation lib/relations does not implement. The ;; internal-only likes data+action endpoints stay proxied too — likes has no SX ;; subsystem to dispatch to. (define host/ledger (list (host/ledger-entry "host" "GET" "/health" nil "native" "host/health-route") (host/ledger-entry "blog" "GET" "/:slug" "blog:post_detail" "migrated" "host/blog-post") (host/ledger-entry "feed" "GET" "/feed" "feed:timeline" "migrated" "host/feed-timeline") (host/ledger-entry "feed" "POST" "/feed" "feed:create" "migrated" "host/feed-create") (host/ledger-entry "relations" "GET" "/internal/data/get-children" "relations:get_children" "migrated" "host/relations-children") (host/ledger-entry "relations" "GET" "/internal/data/get-parents" "relations:get_parents" "migrated" "host/relations-parents") (host/ledger-entry "relations" "POST" "/internal/actions/attach-child" "relations:attach_child" "migrated" "host/relations-attach") (host/ledger-entry "relations" "POST" "/internal/actions/detach-child" "relations:detach_child" "migrated" "host/relations-detach") (host/ledger-entry "relations" "POST" "/internal/actions/relate" "relations:relate" "proxied" nil) (host/ledger-entry "relations" "POST" "/internal/actions/unrelate" "relations:unrelate" "proxied" nil) (host/ledger-entry "relations" "POST" "/internal/actions/can-relate" "relations:can_relate" "proxied" nil) (host/ledger-entry "likes" "GET" "/internal/data/is-liked" "likes:is_liked" "proxied" nil) (host/ledger-entry "likes" "GET" "/internal/data/liked-slugs" "likes:liked_slugs" "proxied" nil) (host/ledger-entry "likes" "GET" "/internal/data/liked-ids" "likes:liked_ids" "proxied" nil) (host/ledger-entry "likes" "POST" "/internal/actions/toggle" "likes:toggle" "proxied" nil))) ;; ── status / domain queries ───────────────────────────────────────── (define host/ledger-by-status (fn (ledger status) (filter (fn (e) (= (get e :status) status)) ledger))) (define host/ledger-migrated (fn (ledger) (host/ledger-by-status ledger "migrated"))) (define host/ledger-proxied (fn (ledger) (host/ledger-by-status ledger "proxied"))) (define host/ledger-native (fn (ledger) (host/ledger-by-status ledger "native"))) (define host/ledger-by-domain (fn (ledger domain) (filter (fn (e) (= (get e :domain) domain)) ledger))) ;; An endpoint is OFF Quart (served by the host) iff native or migrated. (define host/ledger-served? (fn (e) (or (= (get e :status) "native") (= (get e :status) "migrated")))) ;; First entry matching (method, path), or nil. (define host/ledger-find (fn (ledger method path) (let ((hits (filter (fn (e) (and (= (get e :method) method) (= (get e :path) path))) ledger))) (if (> (len hits) 0) (first hits) nil)))) ;; Distinct domains in the catalogue (order: first-seen, reversed by cons). (define host/ledger-domains (fn (ledger) (reduce (fn (acc e) (let ((d (get e :domain))) (if (some (fn (x) (= x d)) acc) acc (cons d acc)))) (list) ledger))) ;; ── coverage ──────────────────────────────────────────────────────── ;; served = off Quart (migrated + native); percent = served / total, floored. (define host/ledger-coverage (fn (ledger) (let ((total (len ledger)) (migrated (len (host/ledger-migrated ledger))) (proxied (len (host/ledger-proxied ledger))) (native (len (host/ledger-native ledger)))) {:total total :migrated migrated :proxied proxied :native native :served (+ migrated native) :percent (if (= total 0) 0 (quotient (* 100 (+ migrated native)) total))})))