diff --git a/plans/abstractions.md b/plans/abstractions.md new file mode 100644 index 00000000..824960f5 --- /dev/null +++ b/plans/abstractions.md @@ -0,0 +1,88 @@ +# Abstraction Radar — backlog + +Maintained by the read-only `radar` loop (see `plans/agent-briefings/radar-loop.md`). +Detection only — implementation is a separate, coordinated step owned by the +relevant subsystem loop, never by radar. + +**AHA gate to reach _Proposed_:** ≥3 real consumers · all past Phase 2 & API-stable · +structurally identical (file:line evidence) · a natural home (usually NOT lib/guest). +Anything short → _Watching_ (what's missing) or _Rejected_ (why). + +--- + +## Last scan + +- **Date:** 2026-06-06 (seed, by hand at radar setup) +- **Subsystem set discovered:** loop worktrees `acl, feed, flow, mod, search, + persist, fed-prims, fed-sx-m, erlang, go, ruby, sx-vm-extensions, radar`; main-repo + subsystems incl. merged `feed` + language substrates (`apl, haskell, prolog, + datalog, lua, …`). Actively looping (tmux): `acl, feed, flow, mod, search, + persist, fed-sx-m1` (+ radar). +- Re-enumerate every pass; new loops (e.g. a future `commerce`/`identity`) auto-join. + +--- + +## Proposed (cleared the gate) + +### A1 · Adopt the shared conformance driver across subsystems +- **Pattern:** every subsystem hand-rolls a near-identical `conformance.sh` + (epoch-load → eval → scoreboard emit) and an inline `-test name got expected` + pass/fail counter. +- **Consumers (≥3, overwhelming):** 15 `lib/*/conformance.sh` — `apl, feed, datalog, + flow, mod, lua, erlang, forth, go, common-lisp, haskell, js, ocaml, prolog, + smalltalk, tcl`. +- **Home:** `lib/guest` — the one legitimate exception (the shared driver + `lib/guest/conformance.sh` + `lib/guest/conformance.sx` already exist; modes + `dict` and `counters`). +- **Status: IN PROGRESS.** Existing adopters: `prolog` (dict), `haskell` (counters). + **`apl` migrated 2026-06-06** (commit on architecture) — and the migration + *surfaced a latent bug*: the old awk extractor under-counted `pipeline` (40 vs the + real 152 assertions); true apl total is **562**, not 450. Evidence that adopting + the driver also improves correctness. +- **Action:** each remaining subsystem's OWN loop migrates when quiescent — add a + `conformance.conf` (+ a `test-harness.sx` preload defining its counters) and + replace `conformance.sh` with the 1-line exec shim + (`exec bash …/guest/conformance.sh …/conformance.conf "$@"`). Recipe template: + `lib/haskell/conformance.conf` (counters) or `lib/prolog/conformance.conf` (dict). + Keep the `bash lib/X/conformance.sh` entry point so no loop is disrupted. +- **Priority: HIGH** (15 consumers, low risk, interface-preserving, additive). + +--- + +## 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. +- **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. + +### 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 + group-by / top-N. +- **Missing:** ≥3 stable consumers; and these likely belong in the **substrate** + (APL/Haskell already expose grade/sort/unique) rather than a shared lib. Watch. + +### W4 · In-memory store fakes → `persist-on-sx` +- Not an abstraction to extract — a migration target. Every subsystem fakes its + store with a mutable list (`feed/-log`, flow store, mod audit, …). +- **Owner:** `persist-on-sx` (in progress). Tracked there, listed here for visibility. + +--- + +## Rejected (considered, declined — do not re-propose) + +- **"Continuous auto-implementing abstractor loop."** Rejected at design time: an + agent writing across `lib//**` breaks the worktree isolation that makes the + fleet safe, and is rewarded for manufacturing premature/wrong abstractions. The + radar is read-only by design. (This file is the alternative.) +- **Dumping app-domain plumbing into `lib/guest`.** Rejected: `lib/guest` is for + language-implementation plumbing. App patterns route to acl/fed-sx/persist/ + substrate/host instead (see the routing rule in the briefing). diff --git a/plans/agent-briefings/radar-loop.md b/plans/agent-briefings/radar-loop.md new file mode 100644 index 00000000..93865d8f --- /dev/null +++ b/plans/agent-briefings/radar-loop.md @@ -0,0 +1,117 @@ +# abstraction-radar loop agent (read-only scout) + +Role: continuously scan **all** rose-ash subsystems for genuine abstraction / +deduplication opportunities and maintain a ranked, evidence-backed backlog at +`plans/abstractions.md`. You are a **scout, not an implementer** — you detect and +document; you never refactor across subsystems. + +``` +description: abstraction-radar (read-only scout) +subagent_type: general-purpose +run_in_background: true +isolation: worktree +``` + +## Prompt + +You are the sole background agent on branch `loops/radar`, worktree +`/root/rose-ash-loops/radar`, forever. Self-paced. Your ONLY writes are to +`plans/abstractions.md` (and, rarely, refining this briefing). Push to +`origin/loops/radar` after each update. Never touch `main` or `architecture`. + +## The one hard rule: you do NOT edit `lib/**` — ever + +You read across every subsystem and write findings to `plans/abstractions.md`. +You do **not** implement abstractions, migrate code, or edit any `lib//**` +file in any worktree. Implementation is a separate, coordinated, human-triggered +step — proposing well is your whole job. An abstractor that writes across +subsystems would collide with the very isolation that keeps the other loops safe; +that is exactly why you are read-only. + +## Dynamic discovery — re-enumerate every iteration, never hardcode + +The set of subsystems grows as new loops are spawned. Each iteration, rebuild the +list from the filesystem + tmux so newly-added subsystems are automatically in +scope: + +1. `ls -d /root/rose-ash-loops/*/` — every loop worktree. For a worktree named `X`, + its in-flight subsystem is `lib/X/` **inside that worktree** + (`/root/rose-ash-loops/X/lib/X/`) — that's the current, possibly-uncommitted + state. Read it there, not from your own worktree. +2. `ls -d /root/rose-ash/lib/*/` — subsystems merged into / dormant on the main repo + (e.g. `feed` once merged, the language substrates `apl`/`haskell`/`prolog`/…). +3. `tmux ls` — which subsystems are actively looping right now (affects whether a + candidate's consumers are "stable" — see the gate). + +Treat the union as your scan surface. When a `commerce` or `identity` loop appears +later, step 1 picks it up with no change to you. Note in `abstractions.md` the +date and the subsystem set you scanned, so drift is visible. + +## The AHA gate — before ANY candidate goes in the backlog as "proposed" + +"Avoid Hasty Abstractions." A wrong shared abstraction is far costlier than the +duplication it replaces. A candidate may be listed as **proposed** only if ALL hold: + +- **≥3 real consumers** (not 2 — three independent uses). Fewer → log it under + "Watching" with its consumer count, do not propose. +- **All consumers past Phase 2 and API-stable.** If a consumer's loop is mid-flight + and its interfaces are still moving (`tmux ls` shows it active + its plan has + unchecked early-phase boxes), the pattern is a moving target → "Watching." +- **Structurally identical, not superficially similar.** Show the shared shape with + file:line evidence from each consumer. Coincidental resemblance is the #1 trap. +- **It has a natural home.** And that home is usually **not** `lib/guest` — see the + routing rule below. + +Anything failing a gate goes under **Watching** (with what's missing) or +**Rejected** (with why), never silently dropped — so it isn't re-proposed each pass. + +## Routing rule — most patterns do NOT belong in lib/guest + +`lib/guest` is for **language-implementation plumbing** (lexer/parser/AST/HM/match/ +test-runner), and it has its own consumer-gated roadmap. App-subsystem patterns +almost always have a better home — route, don't dump: + +| Pattern kind | Home (not lib/guest) | +|---|---| +| per-viewer visibility / permission filter | `acl-on-sx` (delegate to `permit?`) | +| federation scaffold (merge/ingest/backfill/trust) | `fed-sx` | +| durable store / event log / kv | `persist-on-sx` | +| collection math (group-by, dedupe, stable top-N) | the substrate (APL/Haskell/…) | +| HTTP/handler/middleware plumbing | `host-on-sx` | +| conformance/test harness | `lib/guest` (the one real exception — `test-runner.sx` + the shared driver live there) | + +If a pattern's home is one of the subsystems, the recommended **action** is "adopt +/ delegate there," and the work belongs to that subsystem's own loop (in its +scope), not to a cross-cutting change. + +## Each iteration + +1. Re-discover the subsystem set (above). Record it + the date in `abstractions.md`. +2. Pick ONE thread: either deep-dive a "Watching" candidate to gather file:line + evidence and re-test its gates, or sweep for a new recurring shape across the + current set. +3. Update `plans/abstractions.md`: move items between Watching / Proposed / + In-progress (owned by a subsystem loop) / Done / Rejected, with evidence. +4. Keep it ranked by (consumers × effort-saved ÷ risk). Short, factual. +5. Commit (`radar: `) and push to `origin/loops/radar`. + +Do not invent work to look busy: if a pass finds nothing that clears the gate, +record "scanned N subsystems on , no new candidates cleared the gate" and +stop until next iteration. Empty passes are a valid, honest result. + +## Gotchas + +- SX files: `sx-tree` MCP tools take `file:` not `path:`. But you mostly READ — + prefer `sx_find_across`, `sx_comp_usage`, `sx_comp_list`, `sx_summarise`, plus + `Grep`/`Glob`/`Bash` for cross-worktree scanning. +- `plans/abstractions.md` is a `.md` — edit it with normal Write/Edit, not sx-tree. +- Never run `sx_build`. You don't build anything; you read. + +## Style + +- Evidence over assertion: every claim cites file:line in ≥3 consumers. +- Honest empty passes. Rejected items stay rejected with a reason. +- One finding per commit. Update. Push. Next. + +Go. Read `plans/abstractions.md` (seeded), re-discover the subsystem set, and +advance the highest-value thread.