diff --git a/plans/abstractions.md b/plans/abstractions.md index 799bfbdf..2c12fdcd 100644 --- a/plans/abstractions.md +++ b/plans/abstractions.md @@ -65,17 +65,33 @@ Anything short → _Watching_ (what's missing) or _Rejected_ (why). ## Watching (real but not yet through the gate) ### W1 · Federation scaffold (merge / ingest / backfill / trust-gate) -- Every subsystem's Phase 4 is "federation" with the same shape (cross-instance, - trust-gated, injected transport). feed has `feed/merge|ingest|inbound|backfill`. -- **Missing:** only feed is past its federation phase; mod/search/acl/persist haven't - built theirs yet. Re-check once ≥3 have shipped Phase 4. +- **Consumer count NOW met (4):** `feed/lib/feed/fed.sx` (60L/7 defs), + `search/lib/search/fed.sx` (16L/1), `mod/lib/mod/fed.sx` (145L/19), + `acl/lib/acl/federation.sx` (61L/5). +- **BUT structural identity unverified — and the size spread (16→145 lines) is a red + flag.** search/fed is just relabel+merge of an index; mod/fed is 19 defs; + these may be *superficially* similar (all "federation") not structurally identical. +- **Next pass (highest-value thread):** read all 4 side by side, extract the common + shape (if any) with file:line evidence — trust-gate? injected transport? merge vs + ingest split? — before this can move to Proposed. Do NOT propose on the name alone. - **Home when ripe:** `fed-sx` (NOT lib/guest). ### W2 · Per-viewer visibility / permission filter -- feed has `feed/visible` + injected `permit?`; search and mod will post-filter per - viewer too. -- **Missing:** <3 shipped consumers; and the right move is *delegate to `acl-on-sx`*, - not extract. Re-check when search + mod have their ACL filters. +- **2 shipped consumers, same shape** — `filter `: + - `feed/lib/feed/acl.sx:27` `feed/visible = (feed/filter stream (fn (a) (permit? viewer a)))`, + capstone at `:34` (stream → ACL → rank → top-N). `permit?` injected, sig `(viewer activity)→bool`. + - `search/lib/search/fed.sx:16` `aclFilter permit docs = filter permit docs`; + `topNTfIdfAcl n permit ts idx = take n (aclFilter permit (rankTfIdf ts idx))`. + `permit` injected, sig `DocId→Bool` (viewer baked in by caller). +- **NOT a consumer:** `mod/lib/mod/policy.sx` is moderation policy (reviewer actions), + no per-viewer read filter. So mod won't be the 3rd. +- **Missing:** (a) only 2 consumers, need ≥3; (b) the two interfaces *diverge* — + feed passes `(viewer, item)`, search bakes the viewer in — so any shared form must + pick a convention; (c) both already **inject** the predicate, and the filter body is + literally one line (`filter permit xs`). Leaning toward: the predicate's home is + `acl-on-sx` (`permit?`), and the one-line filter is too thin to extract. +- **Home when ripe:** delegate `permit?` to `acl-on-sx`; do NOT extract the filter. + Re-check if a 3rd genuine per-viewer read filter ships (e.g. events/commerce). ### W3 · Collection helpers (group-by, dedupe-by-key, stable top-N, distinct-order) - feed built all of these on APL primitives. search/commerce/events will want