From 80f6fc927980e36ebf2e8b130364f0085627eed8 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 7 Jun 2026 04:38:32 +0000 Subject: [PATCH] =?UTF-8?q?fed-sx-m2:=20Step=2011a=20=E2=80=94=20Announce?= =?UTF-8?q?=20+=20Endorse=20genesis=20activity-types=20+=204=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new DefineActivity SX files in next/genesis/activity-types/ per design §13.5 / Step 11: announce.sx — Re-broadcast a peer's activity to followers. :object is the CID of the activity being announced. :schema requires :object to be a string. Followers see the Announce in their inbox; their projection decides whether to fetch the wrapped activity body. endorse.sx — Cross-actor signal on a target activity. :object is the target activity's CID; :kind is the endorsement variant (e.g. 'like', 'share'). :schema requires both :object and :kind to be strings. Projections aggregate endorsements into counters / heat / ranking signals. M1's Note object-type is unchanged — Create{Note{...}} is still the publish path for short authored messages. The runtime-publish demo (verb extensibility via Create{DefineActivity{...}} at runtime) from M1 §9a continues to work; these files are the genesis pre-shipped variants for v2 baseline so peers don't have to negotiate verb definitions on first contact. Manifest extended: :activity-types 3 -> 5 entries total genesis 34 -> 36 entries Hardcoded count assertions bumped in: bootstrap_read.sh (activity_types 3->5, first-section-count 3->5) bootstrap_load.sh (activity_types 3->5) bootstrap_populate.sh (total 34->36, activity_types 3->5) bootstrap_start.sh (activity_types 3->5, total 34->36) genesis_parse.sh +4 cases (head form + name for both files). bootstrap_populate.sh internal sx_server timeout bumped 300s -> 600s to fit the larger genesis bundle. 61/61 in genesis_parse.sh, 15/15 in bootstrap_read.sh, 15/15 in bootstrap_load.sh, 14/14 in bootstrap_populate.sh, 12/12 in bootstrap_build.sh. --- next/genesis/activity-types/announce.sx | 14 +++++++++++++ next/genesis/activity-types/endorse.sx | 13 +++++++++++++ next/genesis/manifest.sx | 4 +++- next/tests/bootstrap_load.sh | 2 +- next/tests/bootstrap_populate.sh | 6 +++--- next/tests/bootstrap_read.sh | 4 ++-- next/tests/bootstrap_start.sh | 4 ++-- next/tests/genesis_parse.sh | 14 ++++++++++++- plans/fed-sx-milestone-2.md | 26 ++++++++++++++++++++++++- 9 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 next/genesis/activity-types/announce.sx create mode 100644 next/genesis/activity-types/endorse.sx diff --git a/next/genesis/activity-types/announce.sx b/next/genesis/activity-types/announce.sx new file mode 100644 index 00000000..a5b15e59 --- /dev/null +++ b/next/genesis/activity-types/announce.sx @@ -0,0 +1,14 @@ +;; next/genesis/activity-types/announce.sx +;; +;; Bootstrap definition of the Announce verb per design §13.5 / m2 +;; Step 11. An Announce re-broadcasts a peer's activity to the +;; announcer's followers: the announcer's outbox carries an Announce +;; envelope whose :object is the original activity's CID. Followers +;; can re-fetch the wrapped activity from the original instance if +;; their projection wants to fold the body. + +(DefineActivity + :name "Announce" + :doc "Re-broadcast a peer's activity to followers. :object is the CID of the activity being announced. Recipients see the Announce in their inbox / feed; their projection decides whether to fetch the wrapped activity body." + :schema (fn (act) (string? (-> act :object))) + :semantics (fn (state act) state)) diff --git a/next/genesis/activity-types/endorse.sx b/next/genesis/activity-types/endorse.sx new file mode 100644 index 00000000..16a3b886 --- /dev/null +++ b/next/genesis/activity-types/endorse.sx @@ -0,0 +1,13 @@ +;; next/genesis/activity-types/endorse.sx +;; +;; Bootstrap definition of the Endorse verb per design §13.5 / m2 +;; Step 11. An Endorse expresses cross-actor signal on a target +;; activity (like / share / etc.). :object is the target activity's +;; CID; :kind is the endorsement variant (string). Projections +;; aggregate endorsements into counters / heat / ranking signals. + +(DefineActivity + :name "Endorse" + :doc "Cross-actor signal on a target activity. :object is the target activity's CID; :kind is the endorsement variant (e.g. 'like', 'share'). Projections aggregate endorsements into counters / heat / ranking signals." + :schema (fn (act) (and (string? (-> act :object)) (string? (-> act :kind)))) + :semantics (fn (state act) state)) diff --git a/next/genesis/manifest.sx b/next/genesis/manifest.sx index 1684af3d..7cdceff2 100644 --- a/next/genesis/manifest.sx +++ b/next/genesis/manifest.sx @@ -20,7 +20,9 @@ :kernel-version "1.0.0-m1" :activity-types ("activity-types/create.sx" "activity-types/update.sx" - "activity-types/delete.sx") + "activity-types/delete.sx" + "activity-types/announce.sx" + "activity-types/endorse.sx") :object-types ("object-types/sx-artifact.sx" "object-types/note.sx" "object-types/tombstone.sx" diff --git a/next/tests/bootstrap_load.sh b/next/tests/bootstrap_load.sh index b5229914..26c29ec9 100755 --- a/next/tests/bootstrap_load.sh +++ b/next/tests/bootstrap_load.sh @@ -106,7 +106,7 @@ check 10 "strip suffix create.sx -> create" "true" check 11 "strip suffix hello unchanged" "true" check 12 "strip suffix .sx -> empty" "true" check 13 "load_genesis rejects bad shape" "ok" -check 20 "loaded activity_types count = 3" "3" +check 20 "loaded activity_types count = 5" "5" check 21 "loaded object_types count = 13" "13" check 22 "loaded projections count = 7" "7" check 23 "loaded validators count = 3" "3" diff --git a/next/tests/bootstrap_populate.sh b/next/tests/bootstrap_populate.sh index 0362be3b..724541d9 100755 --- a/next/tests/bootstrap_populate.sh +++ b/next/tests/bootstrap_populate.sh @@ -75,7 +75,7 @@ cat > "$TMPFILE" <>) of {ok, B} -> is_binary(B); _ -> false end\") :name)") EPOCHS -OUTPUT=$(timeout 300 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) +OUTPUT=$(timeout 600 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { local epoch="$1" desc="$2" expected="$3" @@ -99,8 +99,8 @@ check() { check 2 "gen_server loaded" "gen_server" check 3 "registry loaded" "registry" check 4 "bootstrap loaded" "bootstrap" -check 10 "populate returns total 34" "34" -check 20 "activity_types count = 3" "3" +check 10 "populate returns total 36" "36" +check 20 "activity_types count = 5" "5" check 21 "object_types count = 13" "13" check 22 "projections count = 7" "7" check 23 "validators count = 3" "3" diff --git a/next/tests/bootstrap_read.sh b/next/tests/bootstrap_read.sh index 6e2a7810..cccc2ae9 100755 --- a/next/tests/bootstrap_read.sh +++ b/next/tests/bootstrap_read.sh @@ -102,7 +102,7 @@ check 10 "sections/0 length" "7" check 11 "ends_with_sx create.sx" "true" check 12 "ends_with_sx hello" "false" check 13 "ends_with_sx empty" "false" -check 20 "section activity_types count" "3" +check 20 "section activity_types count" "5" check 21 "section object_types count" "13" check 22 "section projections count" "7" check 23 "section validators count" "3" @@ -111,7 +111,7 @@ check 25 "section sig_suites count" "2" check 26 "section audience count" "3" check 30 "read_genesis returns 7 sections" "7" check 31 "first section name" "activity_types" -check 32 "first section entry count" "3" +check 32 "first section entry count" "5" TOTAL=$((PASS+FAIL)) if [ $FAIL -eq 0 ]; then diff --git a/next/tests/bootstrap_start.sh b/next/tests/bootstrap_start.sh index c3cc97fe..453d3f7f 100755 --- a/next/tests/bootstrap_start.sh +++ b/next/tests/bootstrap_start.sh @@ -115,10 +115,10 @@ check() { check 10 "bootstrap module loaded" "bootstrap" check 20 "whereis(nx_kernel) is Pid" "true" -check 21 "activity_types count = 3" "3" +check 21 "activity_types count = 5" "5" check 22 "object_types count = 13" "13" check 23 "projections count = 7" "7" -check 24 "total entries = 34" "34" +check 24 "total entries = 36" "36" check 25 "fresh log_tip = 0" "0" check 26 "publish advances tip to 1" "1" check 27 "actor_id = alice" "true" diff --git a/next/tests/genesis_parse.sh b/next/tests/genesis_parse.sh index 65c7dc37..570d2e57 100755 --- a/next/tests/genesis_parse.sh +++ b/next/tests/genesis_parse.sh @@ -40,6 +40,14 @@ cat > "$TMPFILE" <<'EPOCHS' (eval "(first (parse (file-read \"next/genesis/activity-types/delete.sx\")))") (epoch 18) (eval "(get (apply dict (rest (parse (file-read \"next/genesis/activity-types/delete.sx\")))) :name)") +(epoch 27) +(eval "(first (parse (file-read \"next/genesis/activity-types/announce.sx\")))") +(epoch 28) +(eval "(get (apply dict (rest (parse (file-read \"next/genesis/activity-types/announce.sx\")))) :name)") +(epoch 29) +(eval "(first (parse (file-read \"next/genesis/activity-types/endorse.sx\")))") +(epoch 200) +(eval "(get (apply dict (rest (parse (file-read \"next/genesis/activity-types/endorse.sx\")))) :name)") (epoch 19) (eval "(len (get (apply dict (rest (parse (file-read \"next/genesis/manifest.sx\")))) :activity-types))") (epoch 30) @@ -168,7 +176,11 @@ check 15 "update.sx head form" "DefineActivity" check 16 "update.sx name is Update" "Update" check 17 "delete.sx head form" "DefineActivity" check 18 "delete.sx name is Delete" "Delete" -check 19 "manifest has 3 activity-types" "3" +check 27 "announce.sx head form" "DefineActivity" +check 28 "announce.sx name is Announce" "Announce" +check 29 "endorse.sx head form" "DefineActivity" +check 200 "endorse.sx name is Endorse" "Endorse" +check 19 "manifest has 5 activity-types" "5" check 30 "sx-artifact.sx head form" "DefineObject" check 31 "sx-artifact.sx name" "SXArtifact" check 32 "note.sx name" "Note" diff --git a/plans/fed-sx-milestone-2.md b/plans/fed-sx-milestone-2.md index a76f761c..624fa60d 100644 --- a/plans/fed-sx-milestone-2.md +++ b/plans/fed-sx-milestone-2.md @@ -726,7 +726,16 @@ re-broadcast another actor's content to their own followers. **Deliverables:** -- Three new SX files in a `next/genesis/runtime-verbs/` directory. +- [x] **11a** — Announce + Endorse genesis activity-types + (Note already exists as an object-type from M1 — Create{Note} + is the publish path). Two new `DefineActivity` SX files in + `next/genesis/activity-types/` with `:name`, `:doc`, + `:schema` (Announce: `:object` must be a string CID; Endorse: + `:object` and `:kind` must both be strings). Manifest updated + to 5 activity-types / 36 total entries. Hardcoded count + assertions bumped in `bootstrap_read.sh`, `bootstrap_load.sh`, + `bootstrap_populate.sh`, `bootstrap_start.sh`. `genesis_parse.sh` + +4 cases for the two new files (head form + name). - Each is shipped to a fresh instance via a bootstrap manifest entry *or* published as the first activity on the actor's outbox; either works because of the verb-extensibility mechanism. @@ -985,6 +994,21 @@ proceed. Newest first. +- **2026-06-07** — Step 11a: Announce + Endorse genesis + activity-types. Two new DefineActivity SX files in + `next/genesis/activity-types/`: announce.sx (`:object` is a + CID string — the referenced activity to re-broadcast), + endorse.sx (`:object` is a CID, `:kind` is a string variant + like 'like' or 'share'). Manifest extended to 5 activity-types / + 36 total entries. Bootstrap suite count assertions bumped + (`bootstrap_read`, `bootstrap_load`, `bootstrap_populate`, + `bootstrap_start`). `genesis_parse.sh` +4 cases. M1's Note + object-type is unchanged — Create{Note{...}} is still the + publish path. The runtime-publish demo (verb extensibility + via `Create{DefineActivity{...}}` at runtime) from M1 §9a + still works; these files are the genesis pre-shipped + variants for v2 baseline. + - **2026-06-07** — Step 10b: webfinger HTTP route. `GET /.well-known/webfinger?resource=acct:user@host` lands in `http_server.erl` next to the existing