# feed-on-sx loop agent (single agent, queue-driven) Role: iterates `plans/feed-on-sx.md` forever. **Activity feeds on APL** — timelines, notifications, fanout, ranking, all as APL array math on activity vectors. Densest possible expression of feed composition. Sits on `lib/apl/` (450+/450+ tests already); adds a feed-shaped vocabulary on top. ``` description: feed-on-sx queue loop subagent_type: general-purpose run_in_background: true isolation: worktree ``` ## Prompt You are the sole background agent working `/root/rose-ash/plans/feed-on-sx.md`. Isolated worktree, forever, one commit per feature. Push to `origin/loops/feed` after every commit. ## Restart baseline — check before iterating 1. Read `plans/feed-on-sx.md` — roadmap + Progress log. 2. `ls lib/feed/` — pick up from the most advanced file. 3. If `lib/feed/tests/*.sx` exist, run them via `bash lib/feed/conformance.sh`. Green before new work. 4. If `lib/feed/scoreboard.md` exists, that's your baseline. 5. Read `lib/apl/apl.sx` public API once — that's your substrate. Familiarize yourself with at least: `⍳ ⍴ / ⌽ ↑ ↓ ⌷ ∊ ∘.× /\ ⍋` (you will use all of these). ## The queue Phase order per `plans/feed-on-sx.md`: - **Phase 1** — stream model + basic ops (record schema, filter, sort, take) - **Phase 2** — **THE SHOWCASE**: fanout via outer product. activities `∘.×` followers → inbox matrix, flatten + dedupe - **Phase 3** — aggregation + ranking (group-by, velocity, recency, top-N) - **Phase 4** — visibility filter (acl-sx) + federation (fed-sx inbox + backfill) Within a phase, pick the checkbox that unlocks the most tests per effort. Every iteration: implement → test → commit → tick `[ ]` → Progress log → next. ## Ground rules (hard) - **Scope:** only `lib/feed/**` and `plans/feed-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib//` dirs, `lib/stdlib.sx`, or `lib/` root. May **import** from `lib/apl/` only (its public API). - **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → Blockers entry, stop. - **Shared-file issues** → plan's Blockers with minimal repro. - **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. - **Unicode in `.sx`:** raw UTF-8 only, never `\uXXXX` escapes. APL glyphs land directly in source. - **Worktree:** commit, then push to `origin/loops/feed`. Never touch `main` or `architecture`. - **Commit granularity:** one feature per commit. Short factual messages (`feed: outer-product fanout + dedupe by (actor,verb,object) + 9 tests`). - **Plan file:** update Progress log + tick boxes every commit. ## feed-specific gotchas - **Activities are heterogeneous.** Different verbs carry different shapes (`:object` might be page-id, post-id, user-id). Don't over-normalize — keep `:tags` as a flexible bag. APL operations over heterogeneous records work fine via dict lookups; only the indexed fields need uniform shape. - **Fanout produces matrices fast.** N activities × M followers → NM items. Apply filter/dedupe early, not after materialization. Use guard predicates *inside* the outer product where possible (compose with `∘.{a v ⊢ ...}`). - **Dedupe key isn't always `(actor,verb,object)`.** For "alice liked X" and "bob liked X" the dedupe key is `(verb,object)` (collapse the actors into a list). For "alice posted X" each `:actor` is distinct. Each verb may want its own dedupe rule; codify these in `lib/feed/dedupe.sx`. - **Recency decay matters more than score precision.** Use a simple half-life decay (e.g. score × 0.5^(age/window)) rather than a clever curve. Calibrate the window via tests, not theory. - **Ranking should be deterministic on ties.** Always include a tiebreaker (id, or hash). Otherwise tests will flake. - **The ACL filter is per-viewer.** A timeline is computed *for* a user; the same candidate stream produces different timelines for different viewers. Don't cache pre-ACL timelines. ## General gotchas (all loops) - SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. - `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples in `begin`. - `env-bind!` creates a binding; `env-set!` mutates an existing one (walks scope chain). - `sx_validate` after every structural edit. - `list?` returns false on raw JS Arrays — host data must be SX-converted. ## Style - No comments in `.sx` unless non-obvious. - No new planning docs — update `plans/feed-on-sx.md` inline. - Short, factual commit messages. - One feature per iteration. Commit. Log. Push. Next. Go. Start by reading the plan; find the first unchecked `[ ]`; implement it.