diff --git a/next/genesis/manifest.sx b/next/genesis/manifest.sx index 4dbeb568..1684af3d 100644 --- a/next/genesis/manifest.sx +++ b/next/genesis/manifest.sx @@ -24,6 +24,9 @@ :object-types ("object-types/sx-artifact.sx" "object-types/note.sx" "object-types/tombstone.sx" + "object-types/person.sx" + "object-types/service.sx" + "object-types/group.sx" "object-types/define-activity.sx" "object-types/define-object.sx" "object-types/define-projection.sx" diff --git a/next/genesis/object-types/group.sx b/next/genesis/object-types/group.sx new file mode 100644 index 00000000..2f016bc1 --- /dev/null +++ b/next/genesis/object-types/group.sx @@ -0,0 +1,11 @@ +;; next/genesis/object-types/group.sx +;; +;; Per design §9.1: a Group is a multi-controller actor — typically +;; a working group, channel, or collective whose membership is +;; managed via Add/Remove activities. Sig-suite validation honours +;; the current key-set rather than a single keypair. + +(DefineObject + :name "Group" + :doc "Multi-controller actor. :name is the group's display name; :preferredUsername is the local handle; :summary is the description; :icon is a CID or URL; :members is the current member list (managed via Add/Remove)." + :schema (fn (obj) (string? (-> obj :name)))) diff --git a/next/genesis/object-types/person.sx b/next/genesis/object-types/person.sx new file mode 100644 index 00000000..c177fb4a --- /dev/null +++ b/next/genesis/object-types/person.sx @@ -0,0 +1,11 @@ +;; next/genesis/object-types/person.sx +;; +;; Per design §9.1: a Person is the canonical actor type for a +;; human-controlled identity. Bootstrapped via Create{Person{...}} +;; as the actor's first activity (see nx_kernel:bootstrap_actor/4). +;; ActivityPub-Person-compatible. + +(DefineObject + :name "Person" + :doc "Human-controlled actor. :name is the display name; :preferredUsername is the local handle; :summary is the profile bio; :icon is a CID or URL." + :schema (fn (obj) (string? (-> obj :name)))) diff --git a/next/genesis/object-types/service.sx b/next/genesis/object-types/service.sx new file mode 100644 index 00000000..c8284691 --- /dev/null +++ b/next/genesis/object-types/service.sx @@ -0,0 +1,11 @@ +;; next/genesis/object-types/service.sx +;; +;; Per design §9.1: a Service is a non-human actor — a bot, an +;; automated feed, an organisational publisher. Same activity +;; surface as Person, different ActivityPub Actor type. Tooling +;; treats a Service identically to a Person except for UX hints. + +(DefineObject + :name "Service" + :doc "Automated / programmatic actor. :name is the display name; :preferredUsername is the local handle; :summary is the profile bio; :icon is a CID or URL." + :schema (fn (obj) (string? (-> obj :name)))) diff --git a/next/tests/bootstrap_load.sh b/next/tests/bootstrap_load.sh index aa2ed87b..b5229914 100755 --- a/next/tests/bootstrap_load.sh +++ b/next/tests/bootstrap_load.sh @@ -107,7 +107,7 @@ 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 21 "loaded object_types count = 10" "10" +check 21 "loaded object_types count = 13" "13" check 22 "loaded projections count = 7" "7" check 23 "loaded validators count = 3" "3" check 24 "loaded codecs count = 3" "3" diff --git a/next/tests/bootstrap_populate.sh b/next/tests/bootstrap_populate.sh index e189bfa9..0362be3b 100755 --- a/next/tests/bootstrap_populate.sh +++ b/next/tests/bootstrap_populate.sh @@ -99,9 +99,9 @@ check() { check 2 "gen_server loaded" "gen_server" check 3 "registry loaded" "registry" check 4 "bootstrap loaded" "bootstrap" -check 10 "populate returns total 31" "31" +check 10 "populate returns total 34" "34" check 20 "activity_types count = 3" "3" -check 21 "object_types count = 10" "10" +check 21 "object_types count = 13" "13" check 22 "projections count = 7" "7" check 23 "validators count = 3" "3" check 24 "codecs count = 3" "3" diff --git a/next/tests/bootstrap_read.sh b/next/tests/bootstrap_read.sh index 5d0edc5b..6e2a7810 100755 --- a/next/tests/bootstrap_read.sh +++ b/next/tests/bootstrap_read.sh @@ -103,7 +103,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 21 "section object_types count" "10" +check 21 "section object_types count" "13" check 22 "section projections count" "7" check 23 "section validators count" "3" check 24 "section codecs count" "3" diff --git a/next/tests/bootstrap_start.sh b/next/tests/bootstrap_start.sh index 8467e60c..51eafd5d 100755 --- a/next/tests/bootstrap_start.sh +++ b/next/tests/bootstrap_start.sh @@ -116,9 +116,9 @@ check() { check 10 "bootstrap module loaded" "bootstrap" check 20 "whereis(nx_kernel) is Pid" "true" check 21 "activity_types count = 3" "3" -check 22 "object_types count = 10" "10" +check 22 "object_types count = 13" "13" check 23 "projections count = 7" "7" -check 24 "total entries = 31" "31" +check 24 "total entries = 34" "34" 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 2cb3eba7..65c7dc37 100755 --- a/next/tests/genesis_parse.sh +++ b/next/tests/genesis_parse.sh @@ -64,6 +64,20 @@ cat > "$TMPFILE" <<'EPOCHS' (eval "(get (apply dict (rest (parse (file-read \"next/genesis/object-types/define-sig-suite.sx\")))) :name)") (epoch 40) (eval "(get (apply dict (rest (parse (file-read \"next/genesis/object-types/snapshot.sx\")))) :name)") +(epoch 42) +(eval "(first (parse (file-read \"next/genesis/object-types/person.sx\")))") +(epoch 43) +(eval "(get (apply dict (rest (parse (file-read \"next/genesis/object-types/person.sx\")))) :name)") +(epoch 44) +(eval "(first (parse (file-read \"next/genesis/object-types/service.sx\")))") +(epoch 45) +(eval "(get (apply dict (rest (parse (file-read \"next/genesis/object-types/service.sx\")))) :name)") +(epoch 46) +(eval "(first (parse (file-read \"next/genesis/object-types/group.sx\")))") +(epoch 47) +(eval "(get (apply dict (rest (parse (file-read \"next/genesis/object-types/group.sx\")))) :name)") +(epoch 48) +(eval "(some (fn (p) (= p \"object-types/person.sx\")) (get (apply dict (rest (parse (file-read \"next/genesis/manifest.sx\")))) :object-types))") (epoch 41) (eval "(len (get (apply dict (rest (parse (file-read \"next/genesis/manifest.sx\")))) :object-types))") (epoch 50) @@ -166,7 +180,14 @@ check 37 "define-validator.sx name" "DefineValidator" check 38 "define-codec.sx name" "DefineCodec" check 39 "define-sig-suite.sx name" "DefineSigSuite" check 40 "snapshot.sx name" "Snapshot" -check 41 "manifest has 10 object-types" "10" +check 42 "person.sx head form" "DefineObject" +check 43 "person.sx name" "Person" +check 44 "service.sx head form" "DefineObject" +check 45 "service.sx name" "Service" +check 46 "group.sx head form" "DefineObject" +check 47 "group.sx name" "Group" +check 48 "manifest lists person.sx" "true" +check 41 "manifest has 13 object-types" "13" check 50 "activity-log.sx head form" "DefineProjection" check 51 "activity-log.sx name" "activity-log" check 52 "by-type.sx name" "by-type" diff --git a/plans/fed-sx-milestone-2.md b/plans/fed-sx-milestone-2.md index e6d0db69..f799c1e5 100644 --- a/plans/fed-sx-milestone-2.md +++ b/plans/fed-sx-milestone-2.md @@ -158,21 +158,32 @@ publicKey rotation history, profile fields, follower counts, etc. **Deliverables:** -- Genesis additions: `DefineObject{Person}` / `DefineObject{Service}` / - `DefineObject{Group}` — three object-type SX files. -- Actor-state projection fold (Erlang-fun stand-in, mirrors Step 5d-pure): - - On `Create{Person|Service|Group}`: register the actor's profile. - - On `Update{Person, patch}`: apply patch. +- [x] **2a** — Genesis additions: `DefineObject{Person}` / + `DefineObject{Service}` / `DefineObject{Group}` — three new SX + files in `next/genesis/object-types/` plus manifest entries (now + 13 object-types total, 34 total genesis entries). Each defines + `:name`, `:doc`, `:schema (fn (obj) (string? (-> obj :name)))`. + `next/tests/genesis_parse.sh` extended +7 cases (head form + + :name + manifest membership), now 57/57. Bootstrap suite + count assertions bumped (`bootstrap_read.sh` 15/15, + `bootstrap_load.sh` 15/15, `bootstrap_populate.sh` 14/14, + `bootstrap_start.sh` 10/10). `bootstrap_build.sh` 12/12 picks + up the new bundle CID dynamically. +- [ ] **2b** — Actor-state projection fold (Erlang-fun stand-in, + mirrors Step 5d-pure's `define_registry`): + - On `Create{Person|Service|Group}`: register the actor's profile + in `{ActorId => #{type, name, preferredUsername, summary, icon, + public_keys, created}}`. + - On `Update{Person|Service|Group, patch}`: deep-merge the patch. - On `Move`: record `:movedTo` pointer. -- `nx_kernel:bootstrap_actor/4(ActorId, Profile, KeySpec, State)` — - publishes `Create{Person{...}}` as the actor's first activity, - bootstrapping their own log. - -**Tests:** - -- `Create{Person}` registers the actor. -- Two actors created via lifecycle activities have independent state. -- Profile updates apply. + - `next/kernel/actor_state.erl` with `fold_fn/0` plugging into + `projection:start_link/3`. Pure-functional + gen_server-bridged + tests as a single `actor_state_pure.sh`. +- [ ] **2c** — `nx_kernel:bootstrap_actor/4(ActorId, Profile, + KeySpec, State)` — publishes `Create{Person{...}}` as the actor's + first activity, exercising the full pipeline. Integration test + in `actor_lifecycle.sh` ties 2a artefacts (SX files), 2b + projection, and 2c bootstrap together. **Acceptance:** `bash next/tests/actor_lifecycle.sh` passes 10+ cases. @@ -680,6 +691,17 @@ proceed. Newest first. +- **2026-06-06** — Step 2a: genesis Person/Service/Group object- + types. Three new SX files in `next/genesis/object-types/` with + the same shape as `note.sx` / `sx-artifact.sx` (`:name`, `:doc`, + `:schema` checking `(string? (-> obj :name))`). Manifest extended + to 13 object-types / 34 total entries. `genesis_parse.sh` +7 + cases (57/57). Hardcoded counts bumped in `bootstrap_read.sh`, + `bootstrap_load.sh`, `bootstrap_populate.sh`, `bootstrap_start.sh` + (66/66 across those four). `bootstrap_build.sh` 12/12 (bundle CID + computed dynamically). Conformance 761/761 preserved. 211 / 211 + across 12 Step-2-adjacent suites. + - **2026-06-06** — Step 1b: gen_server multi-actor calls. `nx_kernel` exports `add_actor/3`, `publish_to/2`, `log_tip_for/1`, `actors/0`, `state_for/1`, `bucket_for/1`,