fed-sx-m2: Step 2a — Person/Service/Group genesis object-types
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 35s

Three new DefineObject artefacts in next/genesis/object-types/ for
the canonical actor object-types per design §9.1:

- Person: human-controlled identity (display name + handle + bio)
- Service: automated / programmatic actor (bot, feed, organisation)
- Group: multi-controller actor (member-set managed via Add/Remove)

Each is a small SX form with :name / :doc / :schema, identical
shape to existing object-types (note.sx, sx-artifact.sx etc) so the
existing bootstrap:populate_registry walk picks them up without
code changes. Manifest extended (object-types: 10 -> 13, total
entries: 31 -> 34).

Tests:
- genesis_parse.sh +7 cases (head form, :name, manifest membership);
  57/57.
- Hardcoded counts bumped in bootstrap_read.sh, bootstrap_load.sh,
  bootstrap_populate.sh, bootstrap_start.sh.
- bootstrap_build.sh 12/12 (bundle CID computed dynamically).

Conformance 761/761 preserved. 211/211 across 12 Step-2-adjacent
suites.
This commit is contained in:
2026-06-06 11:19:22 +00:00
parent 089d1445a1
commit 0c44a10c8f
10 changed files with 100 additions and 21 deletions

View File

@@ -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"

View File

@@ -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))))

View File

@@ -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))))

View File

@@ -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))))

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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`,