Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
31 KiB
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-07 (radar loop, pass 19)
- Pass 19 — honest empty pass. Scanned 10 active subsystems. content/index.sx is a
blog index/tag-cloud listing (presentation, not full-text search — no search reinvention)
and content/multi-doc indexing adds no per-viewer filter. W2 re-tested: still 2
(feed, search) — acl's
permit?-like matches are its own authZ engine (the home), not a downstream read filter. No new candidate cleared any gate. - Date: 2026-06-07 (radar loop, pass 18)
- Pass 18 — W1 gate re-test. events shipped Phase 4 federation (5th consumer): a 5th
divergent merge (sorted agenda +
:originprovenance), trust-gate = runtime list membership (shares mod's mechanism, not acl's). Reinforces W1's "theme not shape" — but the inject-fed-sx-transport seam is now 5/5, strengthening "all are fed-sx consumers-in-waiting." Trust sub-pattern refined: mod+events (runtime set) vs acl (rule). - Date: 2026-06-07 (radar loop, pass 17)
- Pass 17 — filename census declared EXHAUSTED (see the Census-status table above). Examined the last unswept ≥2 recurrences (schema/engine = acl⇄mod substrate twins; catalog/batch = name collisions; store = divergent). No new candidate. Incremental churn elsewhere (content 621/621, identity PAR, events reminders). Future passes pivot from censusing to re-testing gates as consumers mature.
- Date: 2026-06-07 (radar loop, pass 16)
- Pass 16: events started Phase 3 — durable notification delivery on
lib/flow(new W8: at-least-once + idempotency exemplar; fed-sx/mod roll their own outbox). The twonotify.sx(feed vs events) are a name collision (read-side digest vs delivery), noted in W8. Substrate-adoption story deepening: app domains now consume persist (content/ commerce/events), flow (events), commerce (events), acl-authZ (identity). - Date: 2026-06-07 (radar loop, pass 15)
- Pass 15: added the scanning-method note above after
query.sxagain proved to be merged-lib copies (lib/prolog + lib/persist in every worktree). Corrected census surfacedwire×2 (content+mod) → Rejected (shared role, divergent structure: generic SX serializer vs bespoke pipe-format under a Prolog-env string-prim constraint). events↔ commerce integration appeared (paid tickets); acl/mod/search quiescent ~7 passes (now API-stable). No new gate-clearer. - Date: 2026-06-07 (radar loop, pass 14)
- Pass 14: filename census flagged
snapshot×?? — but the*/lib/persist/snapshot.sxcopies are just the mergedlib/persistin each worktree, NOT consumers (same artifact aslib/feed/rank.sxeverywhere). The one distinct file,content/snapshot.sx, reimplements persist's projection-checkpoint on raw KV instead of usingpersist/snapshot→ new W7 (persist-adoption nudge).audit×3 = the W4 fakes (acl/mod/identity), known. - Date: 2026-06-07 (radar loop, pass 13)
- Pass 13 — honest re-test, no gate-clearer. Re-tested the two longest-waiting gates
against the maturing app-domain loops: W2 (per-viewer visibility) still 2 consumers
(feed, search) — commerce/content/events/identity add no per-viewer read filter; W3
(pagination) still 2 (feed, search) —
content/page.sxis an HTML wrapper, not pagination (filename collision, noted in W3). Incremental churn only elsewhere. - Date: 2026-06-07 (radar loop, pass 12)
- Pass 12:
eventsshipped transactional booking on persist (3rd live persist consumer) usingpersist/append-expect(optimistic-concurrency CAS, lock-free capacity safety). W4 ledger now shows a persist feature-ladder append → append-once → append-expect that the hand-rolled fakes can't match. No new candidate; W4 reinforced. - Date: 2026-06-07 (radar loop, pass 11)
- Pass 11 — W4 sharpened with a consumer ledger. commerce built an order ledger on
persist (2nd live exemplar; uses
persist/append-oncefor webhook idempotency) and identity a grant audit ledger (in-memory Erlang fake, gated on an Erlang↔persist bridge). The append-only monotonic-seq event-log pattern is now validated across 4 domains, 2 live on persist + 3 fakes flagged for adoption. See W4 table. - Date: 2026-06-07 (radar loop, pass 10)
- Pass 10: commerce/content/events/identity advancing (content 238/238). Probed a shape outside the routing table — guarded lifecycle state machines (mod/lifecycle + identity/membership) → new W6: shared design principle, divergent structure (SX transition-table vs Erlang gen_server), NOT an extraction target. No gate-clearer.
- Date: 2026-06-07 (radar loop, pass 9)
- Pass 9:
commerce+contentreached Phase 2 (content162/162). Key find:contentbuilt its op log directly onpersist/log(backend-injected, append+replay- to-seq) — the live reference exemplar for W4 (see W4).eventsMONTHLY RRULE,identityOAuth2 auth-code + PKCE, search boolean-filtered ranked. A1 still 6 adopters. - Date: 2026-06-06 (radar loop, pass 8)
- Pass 8 — fleet expanded by 4 app-domain loops (the briefing's anticipated
commerce/identityarrivals, auto-picked up by dynamic discovery). All early-stage, pre-Phase-2 → moving targets, none count toward any gate yet:commerce(Phase 1:api/cart/catalog/price). Its "per-line audit" is a cost breakdown view (api.sx:44), not an append-only decision log → NOT a W4 consumer.events(Phase 1:calendar.sx, RRULE expansion).identity(early:session/token). Defers authZ to acl (token.sx:15) — reinforces W2's "delegatepermit?to acl-on-sx" routing; identity = authN, acl = authZ.content(just-started:block.sx). These are the future consumers W2/W3 are waiting on — re-check their per-viewer filters / pagination once each clears Phase 2. No new gate-clearer this pass.
- Pass 7: A1 jumped 4→6 adopters —
acl+modmigrated to the shared conformance driver (first app-domain adopters; proves it generalizes past substrates).host-persistclosed its blob-adapter blocker (durable storage adapter now landing → W4 migration path opening). search shipped proximity/NEAR; flow + persist quiescent. - Pass 6: new worktree
host-persist(active — building persist's durable host adapter);feedwent quiescent (left tmux). acl shipped hardening (+25), fed-sx-m1 at Step 6c. mod loop independently wrote a shared-plumbing note (mod-on-sx.md,538b8a53) corroborating W4/W5 — folded its claims + home disagreements into W1/W4/W5. No new gate-clearer (audit log still 2 consumers), but consumers are now API-stable. - Pass 5: search (+highlight/snippet) and fed-sx-m1 (+follower_graph) moved; rest
unchanged. Filename census:
api×6,fed×3, thenschema/rank/query/page/explain/ engine/batch/audit×2. Examined the ×6api.sx→ Rejected (shared name, divergent structure incl. implicit-vs-explicit-state contract). rank/batch/engine all ≤2 + substrate/domain-divergent → no new gate-clearer. - Pass 4: no churn vs pass 3 (same worktrees/tmux/HEADs/adopters). Swept audit+explain surfaces: acl/mod share an append-only-log shape (→ sharpened W4 with persist/log API evidence) and a proof-explain shape (→ new W5, substrate-bound). No new gate-clearer.
- Pass 3 (earlier today): subsystem set + tmux + A1 adopters (4) all unchanged vs pass 2. Loops advanced: acl shipped Phase 4 federation; search shipped Phase 4 + pagination; feed shipped pagination/threading; mod at Ext 19 (capstone); persist did a worked acl-grants migration (W4). New shape found: offset/limit pagination → folded into W3.
- Subsystem set discovered: loop worktrees
acl, erlang, fed-prims, fed-sx-m1, feed, flow, go, kernel, mod, ocaml, persist, radar, ruby, search, sx-vm-extensions; main-repolib/*incl. mergedfeed+ substrates (apl, common-lisp, datalog, erlang, forth, go, haskell, hyperscript, js, lua, minikanren, ocaml, prolog, scheme, smalltalk, tcl) +lib/guest. Actively looping (tmux):acl, fed-sx-m1, feed, flow, mod, persist, search(+ radar). - New since pass 1: worktrees
kernel(empty/unset — not yet a repo) andocaml(lib/ocaml/baselineonly). Both early-stage, pre–Phase 2 → out of proposal scope. - Re-enumerate every pass; new loops (e.g. a future
commerce/identity) auto-join.
Census status (pass 17): EXHAUSTED. Every own-namespace filename recurring ≥2× has been examined and dispositioned — further filename-censusing is low-yield until new subsystems/modules appear. Map:
| filename | owners | verdict |
|---|---|---|
api ×10 |
all | Rejected — shared role, divergent state contract |
fed/federation |
feed/search/mod/acl(+content) | W1 — theme not shape |
audit ×3 |
acl/mod/identity | W4 — append-only log → persist/log |
page ×3 |
feed/search (pagination) + content (HTML wrapper) | W3 + collision noted |
explain ×2 |
acl/mod | W5 — proof tree, substrate-bound |
snapshot ×2 |
persist(facet) + content(reinvents) | W7 |
wire ×2 |
content(SX serializer) / mod(pipe-format) | Rejected — divergent |
schema,engine ×2 |
acl/mod | substrate-twin parallels (Datalog vs Prolog); only audit (W4) is liftable |
catalog,batch ×2 |
commerce/persist, mod/persist | name collisions, unrelated |
store ×2 |
content(on persist) / flow(workflow records) | related concept, divergent |
rank ×2 |
feed/search | different domains (activities vs docs), ≤2 |
| acl⇄mod are structural twins (decision engine over a logic substrate, Datalog vs | ||
| Prolog) — they parallel across engine/schema/explain/audit/fed, but only the audit log | ||
| is substrate-agnostic and liftable (→ W4); the rest are substrate-idiomatic. Next passes: | ||
| re-test gates (W2/W3/W8) as consumers mature, watch new modules — not re-census. |
Scanning-method note (learned the hard way, passes 5/12/14/15): a filename census
for cross-subsystem recurrence MUST restrict to each subsystem's OWN namespace —
X/lib/X/*.sx — never X/lib/*/. The merged substrate libs (lib/prolog, lib/persist,
lib/feed, lib/datalog, …) are checked out inside every worktree, so a naive census
reports e.g. query.sx/snapshot.sx/rank.sx ×N as phantom recurrences that are really
one merged file copied N times. Correct one-liner:
for w in <subsystems>; do for f in $w/lib/$w/*.sx; do basename $f .sx; done; done | sort | uniq -c | sort -rn.
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<x>-test name got expectedpass/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 driverlib/guest/conformance.sh+lib/guest/conformance.sxalready exist; modesdictandcounters). - Status: IN PROGRESS — 6 adopters (pass 7).
prolog(dict),haskell(counters),apl(dict),datalog(dict), andacl(dict) +mod(dict), newly migrated this pass — all 3-line exec shims intolib/guest/conformance.shwith aconformance.conf. acl + mod are the first app-domain adopters (not language substrates) — strong evidence the driver generalizes beyond the substrate layer, which was the open question. Theaplmigration earlier surfaced a latent bug: the old awk extractor under-countedpipeline(40 vs the real 152 assertions); true apl total is 562, not 450 — evidence that adopting the driver also improves correctness. - Not a target (different harness shape):
lua/conformance.shis a Python runner (lib/lua/conformance.py) that walks real*.luasource files vialua-eval-astand classifies pass/fail/timeout — it does not run SXdeftestsuites with a counter/dict scoreboard, so the shared driver does not fit. Excluded, not pending. - Remaining hand-rolled candidates (~120–220 lines each):
common-lisp, erlang, feed, forth, go, js, ocaml, smalltalk, tcl— each its OWN loop's migration when quiescent. (search+luaexcluded: different harness shapes — search assembles a Haskell source string, lua walks real*.luafiles.) - Action: each remaining subsystem's OWN loop migrates when quiescent — add a
conformance.conf(+ atest-harness.sxpreload defining its counters) and replaceconformance.shwith the 1-line exec shim (exec bash …/guest/conformance.sh …/conformance.conf "$@"). Recipe template:lib/haskell/conformance.conf(counters) orlib/prolog/conformance.conf(dict). Keep thebash lib/X/conformance.shentry 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)
-
FAILS the structural-identity gate (deep-dived 2026-06-06, all 4 read). Consumer count is met (4) but they are superficially similar, not structurally identical — the federated unit and merge op differ fundamentally:
Subsystem (file) Federated unit Merge op Trust gate Injected transport feed ( fed.sx:14,18,40)activity streams dedupe by (actor verb object)none (visibility via permit?separately)send-fn,fetch-fnsearch ( fed.sx:8)inverted indices relabel DocId peer*1000+local+ union posting listsnone none (pure merge fn) mod ( fed.sx:11-14,99)moderation decisions advisory-list vs applied-list; bind iff mod/trusted?yes — runtime list mod/trusted? peer scopemock outbox / fed-send!acl ( federation.sx:43,56)Datalog delegate facts pull facts, gate by trust/level_coversrule, re-saturateyes — Datalog rule at query time transportdictevents ( federation.sx)calendar agendas fold trusted peers' agendas into one sorted agenda + :originprovenanceyes — runtime list ev/trusts?(peer-id ∈ trust-set)injected behind ev/peer-agenda -
The ONLY real commonality is the injection seam (now 5/5, pass 18), not extractable code: every one says "the real transport is
fed-sx's job; injectsend-fn/fetch-fn/transport/peer-agendaand mock it in tests." That is an architectural convention the fleet already follows. The merge op diverges 5 ways (dedupe / index-union / advisory / fact-saturation / agenda-sort). The trust gate, where present, splits: mod + events use a runtime trust-set membership check; acl uses a declarative Datalog rule — so even the trust sub-pattern is 2-of-3, and the membership check is a trivial one-liner (below the extraction threshold). No shared merge, no single shared trust mechanism. -
Disposition: do NOT extract a shared "federation lib." When
fed-sxships its real transport, these 4 become its consumers (wiringsend-fn/fetch-fn/transportto it) — that work belongs to each subsystem's loop + thefed-sxloop, not a cross-cutting extraction. Stop re-proposing on the shared name. Home:fed-sx. -
Narrower sub-claim (mod note, pass 6; refined pass 18): mod asserts the fed trust/outbox shape shares between mod+acl. Radar evidence refines this: the trust gate splits by mechanism, not by subsystem pair — mod + events both use a runtime trust-set membership check (
mod/trusted?,ev/trusts?), while acl uses a Datalog rule. So a "trust-set membership" helper has 2 consumers (mod, events) — but it's a one-linemember?and the merge it gates diverges, so still not worth extracting. Resolve at the architecture-merge point if a heavier shared trust-set surface emerges.
W2 · Per-viewer visibility / permission filter
- 2 shipped consumers, same shape —
filter <injected-permit> <ranked/candidate stream>:feed/lib/feed/acl.sx:27feed/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:16aclFilter permit docs = filter permit docs;topNTfIdfAcl n permit ts idx = take n (aclFilter permit (rankTfIdf ts idx)).permitinjected, sigDocId→Bool(viewer baked in by caller).
- NOT a consumer:
mod/lib/mod/policy.sxis 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 isacl-on-sx(permit?), and the one-line filter is too thin to extract. - Home when ripe: delegate
permit?toacl-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, offset/limit page)
- feed built all of these on APL primitives. search/commerce/events will want group-by / top-N.
- NEW (2026-06-06): offset/limit pagination shipped in 2 subsystems, identical shape
take limit (drop offset xs):feed/lib/feed/page.sx:9feed/page(offset/limit window over a stream).search/lib/search/page.sx:9paginate off lim docs = take lim (drop off docs).- NOT a 3rd:
persist/lib/persist/query.sx:5has a since-cursor for incremental log consumption — resumable-stream semantics, not result windowing. Different shape. - feed also has cursor-by-
:atrecency pagination (page.sx:21-44); search has no cursor. So only the plain offset/limit window is shared, and it is a literal 1-liner.
- Missing: ≥3 stable consumers; AND every item here is collection math that belongs
in the substrate (APL/Haskell already expose grade/sort/unique/take/drop), not a
shared lib. A 1-line
take/dropwindow is far below the extraction threshold. Watch; revisit only if a non-substrate subsystem needs the same windowing without take/drop. - Filename-collision caution (pass 13):
content/lib/content/page.sxis an HTML page wrapper (full HTML5 doc), NOT pagination — do not count it as a 3rd pagination consumer.page.sxnow means two unrelated things across the fleet. Re-tested pass 13: pagination still only feed + search (2).
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. -
Concrete instance (file:line, found pass 4): the append-only decision/audit log.
acl/lib/acl/audit.sxandmod/lib/mod/audit.sxare the SAME hand-rolled shape, andpersist/lib/persist/log.sx(the persist log facet) already implements it durably:role acl/audit.sx mod/audit.sx persist/log.sx (target) log var acl-audit-log:9mod/*audit-log*:10backend stream monotonic seq acl-audit-seq:10mod/*audit-seq*:11per-stream high-water :1 append (auto-seq) acl-audit-decide!commit :32 persist/append:17count acl-audit-count:51mod/audit-count:44persist/count:12read-all oldest-first snapshot/tail :73 mod/audit-all:43persist/read:29read seq≥from — by-seq persist/read-from:31Both deliberately use a monotonic seq with no wall-clock (deterministic/testable) — identical to persist/log's design. Action when persist's host adapter lands: acl + mod loops swap their in-memory log for
persist/log. 2 consumers today; not a new lib — the home already exists. Belongs to acl/mod loops × persist loop, not an extraction. -
Cross-loop corroboration (pass 6): the mod loop independently reached the same conclusion —
mod/plans/mod-on-sx.md(commit538b8a53): "mod-sx (Prolog) and acl-sx (Datalog) converged on the same module shape … only the audit log + fed trust/outbox shapes truly share; extract at the architecture-merge point, refactoring both consumers atomically, not unilaterally from a loop branch." Confirms the shape AND the do-not-extract-unilaterally stance. -
Home disagreement to resolve at merge: mod's note proposes lifting the audit-log primitives into
lib/guest/. Radar routing disagrees: a durable append-only log is apersist-on-sxconcern (the log facet already exists), not language-impl plumbing. Hold the line —lib/guestis lexer/parser/AST/HM/test-runner, not an event log. -
Migration is becoming concrete: new
host-persistloop (worktree + tmux, pass 6) is building the durable-storage host adapter persist was blocked on — once it lands, acl/mod can actually swap topersist/log. -
LIVE REFERENCE EXEMPLAR (pass 9):
contentalready does it right.content(Phase 2 complete, 162/162) built its op log directly onpersist/loginstead of faking it —content/lib/content/store.sx: backend injected via(persist/open)("content knows nothing about which backend", :10); append op as eventpersist/append b (content/-stream doc-id) …(:20); readpersist/read(:36);persist/last-seq(:47); version = replay op stream up to a seq (filterpersist/event-seq ev <= seq, :61). "The op log is the source of truth … the materialised doc is a cache, never primary state." This proves the W4 target is real, not hypothetical: acl + mod's hand-rolled monotonic-seq logs should adopt exactly content'spersist/logpattern. -
Consumer ledger of the append-only monotonic-seq event log (pass 11):
consumer what backing note content ( store.sx)doc op log persist/log ✓ live plain append + replay-to-seq commerce ( ledger.sx)order ledger persist/log ✓ live persist/append-once— idempotent, webhook-replay-safe :40,58events ( booking.sx)booking roster persist/log ✓ live persist/append-expect— optimistic-concurrency CAS, capacity-safe, lock-freeacl ( audit.sx)decision log in-memory fake (SX) migrate directly when host adapter lands mod ( audit.sx)decision log in-memory fake (SX) migrate directly identity ( audit.sx)grant ledger in-memory fake (Erlang) {Seq,Subject,Action}; needs an Erlang↔persist bridge first — author scoped it out until persist lands ("queryable semantics identical") -
Two takeaways: (1) the pattern is validated across domains — CRDT doc ops, financial orders, event bookings, rule decisions, OAuth grants all reduce to the same append-only monotonic-seq stream; (2) migrating to
persist/logis strictly better than the fakes — persist exposes a feature ladder the fakes don't have:append(content) →append-once/idempotency (commerce) →append-expect/optimistic- concurrency (events). Every fake would have to reinvent a weaker version of these. This is an adoption item (the home already exists), NOT a new extraction — owned by persist/host-persist × each consumer loop. The SX fakes (acl, mod) migrate directly; the Erlang fake (identity) is gated on an Erlang↔persist bridge.
W5 · Proof-tree explanation over a logic-program derivation
acl/lib/acl/explain.sx(reconstructs a canonical proof by goal-directed search over a saturated Datalog db) andmod/lib/mod/explain.sx(renders a Prolog-style proof tree goal-by-goal with proved/unproved marks + unification bindings) are the same idea.- Missing / disposition: only 2 consumers, and they sit on different substrates
(acl→
lib/datalog, mod→lib/prolog). Proof reconstruction/rendering is logic-engine machinery → it belongs in each substrate (datalog/prolog), not a shared app lib. Watch; revisit only if a 3rd logic-backed subsystem reimplements proof explanation. - Cross-loop note (pass 6): mod's note calls
mod/proof-goals(re-query-each-goal) generic and proposes lifting it intolib/guest/. Radar caveat: proof-tree reconstruction is engine-agnostic logic machinery, butlib/guestis for lexer/parser/AST/HM/match/test-runner — a logic-engine proof helper is a poor fit there. If genuinely shared by ≥3 engines, alib/logic-style substrate helper is the better home thanlib/guest. Still 2 consumers → stays Watching either way.
W8 · Durable outbound delivery (at-least-once + idempotency + retry)
- Live exemplar on
lib/flow:events/lib/events/notify.sx— reminders/digests are durableflows: a flowrequests delivery (suspend point), the host performs the send via an injecteddispatchtransport, then resumes with the outcome; flow's deterministic replay means a completed delivery never re-runs on recovery. At-least-once with an idempotency key per message. This is "reliable delivery" done right on the flow substrate. - Others roll their own:
fed-sxbuilt its own outbox +delivery_worker+ retry bookkeeping (Steps 8a–d);mod/fed.sxhas an in-memory outbox seam;acl/federationpropagates facts. Same goal (reliable outbound delivery, retry/idempotency) on different machinery. - Disposition: durable delivery is exactly what
lib/flowis for (events proves it). Watch whether fed-sx / mod converge their outbox onto flow, or stay bespoke for perf/substrate reasons. 1 clean flow-based consumer today → Watching, not a proposal. - Name-collision caveat:
notify.sxmeans two unrelated things —feed/notify.sxis a read-side digest (group inbox by verb+object), NOT delivery. Do not pair them.
W7 · Snapshot/projection-checkpoint reimplemented vs persist/snapshot (delegate)
persist/lib/persist/snapshot.sxalready provides a generic projection checkpoint: store{:value :seq}in the kv facet under a namespaced key; the headline property is snapshot + tail == full replay (pure, clock-free).content/lib/content/snapshot.sxreimplements that same pattern on raw persist KV rather than delegating:persist/kv-put b (content/-snap-key doc-id) {:doc … :seq seq}(:20),persist/kv-has?/kv-get(:27-28), and its own tail-replay (:53-59). It never callspersist/snapshot-*. content's doc-materialisation is a projection fold over its op stream — exactly whatpersist/snapshotcheckpoints generically.- Disposition: persist-adoption nudge (like W4): content could delegate to
persist/snapshot(its projection = "fold ops → doc"), dropping the duplicated KV+replay code. Home already exists → NOT an extraction; owned by content × persist loops. Only 1 reinventor today; watch whether commerce/events/identity also hand-roll a snapshot on raw KV instead of using the facet (would strengthen the nudge). NB timeline: unclear ifpersist/snapshotpredated content's — flag, don't blame.
W6 · Guarded lifecycle state machine (illegal transition = explicit error)
- Recurs as a design principle, NOT a shared structure (found pass 10):
mod/lib/mod/lifecycle.sx— pure SX: immutable case{:state :error :history …}, explicit transition tablemod/lc-transitions(:31), illegal transition returns the case unchanged with:errorset. States open→triaged→decided→appealed→final.identity/lib/identity/membership.sx— an Erlanggen_serverfragment (identity runs on erlang-on-sx): areceiveloop withcase find(...) of … {error, St}guards. States none→pending→active→lapsed→revoked.
- Both share the guideline ("invalid transitions are explicit errors, never silent
no-ops") but implement it substrate-idiomatically — SX transition-table over
immutable values vs an Erlang process loop with per-message case guards. Same W1/
api.sxtrap: shared idea, divergent structure. - Disposition: not an extraction target — the FSM mechanism is ~10 substrate-specific lines; the value is in each domain's state graph, not the plumbing. At most a design guideline ("model lifecycle as a guarded FSM with explicit-error transitions"). Watch whether commerce-checkout / events-booking add their own — if so it confirms the guideline, still not a lib. Do not propose extracting a shared state-machine lib.
Rejected (considered, declined — do not re-propose)
- "Continuous auto-implementing abstractor loop." Rejected at design time: an
agent writing across
lib/<x>/**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.) - Shared
api.sx"public boundary" module (×6). Rejected pass 4-5: every subsystem has anapi.sx(acl, feed, flow, mod, persist, search — a 100% filename match), but it is a naming convention for the public entry point, not a shared structure. They disagree on the most basic contract: acl/feed use implicit module state (acl/api.sx"implicit current db",feed/api.sx"single mutable log") whilepersist/api.sxthreads an explicit backend as every call's first arg; flow's api builds a Scheme env, search's api concatenates a Haskell source string, mod's is a lifecycle state-machine façade (17 defs vs persist's 1). Same role, no common shape — the W1 coincidental-resemblance trap. Do not re-propose on the filename. - Shared
wire.sx"serialization" module (×2). Rejected pass 15: content + mod both have awire.sx, butcontent/wire.sxuses the generic SX serializer (serialize/parse, full-fidelity round-trip) whilemod/wire.sxis a bespoke versioned pipe-delimited line (subset of fields,splithand-built over slice/len because mod's Prolog-loaded env strips string prims). Shared role (wire format), divergent structure + substrate constraint → not a candidate; the SX serializer is already the shared tool for SX-substrate subsystems, and mod can't use it. (Same family as theapi.sxrejection above.) - Dumping app-domain plumbing into
lib/guest. Rejected:lib/guestis for language-implementation plumbing. App patterns route to acl/fed-sx/persist/ substrate/host instead (see the routing rule in the briefing).