Files
rose-ash/plans/fed-sx-host-types.md
giles 5959a97dca
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s
fed-sx-types Phase 1: DefineType + SubtypeOf genesis verbs
Two new DefineActivity-form genesis activity-types for host-type
federation (plans/fed-sx-host-types.md step 1):

- next/genesis/activity-types/define_type.sx — DefineType verb; schema
  accepts an :object with a string :name and optional list :fields.
- next/genesis/activity-types/subtype_of.sx — SubtypeOf verb; schema
  accepts an :object carrying string :child-type-cid + :parent-type-cid.

Schema bodies use nested `get` (not keyword-threading) so they are
directly evaluatable — keywords are not callable getters in the kernel.
Both registered in manifest.sx (activity-types now 7); the four bootstrap
suites' bundle counts bumped (5->7, total 36->38).

Tests: next/tests/define_type.sh (7), subtype_of.sh (6) — parse shape,
schema accept/reject, term_codec envelope round-trip.

Also load follower_graph + delivery in bootstrap_start.sh: its check-26
publish path exercises outbox:compute_delivery_set/3 (follower_graph:new
+ delivery:delivery_set), which an m2 substrate change had left unloaded
in that suite — a pre-existing red unrelated to the count bump.

Conformance 771/771; all touched next/tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:30:21 +00:00

4.9 KiB

; -- mode: markdown --

fed-sx host-type federation — substrate design + build log

How a host's typed-post graph (refinement types declared in lib/host's metamodel) flows across fed-sx nodes: a type is published as a content-addressed DefineType activity, peers cache its record, serve it over the wire, and validate inbound objects against the declared refinement schema before appending them.

This document is both the design and the running build log for loops/fed-sx-types. The companion build sheet is plans/agent-briefings/fed-sx-types-loop.md.

Vocabulary

  • Type record{name, fields, refinement-schema, instance-type}. The parsed :object payload of a DefineType activity. Immutable per CID: an updated type is a new CID (no in-place evolution).
  • Type CID — content-address of the type record's wire form. The stable handle a SubtypeOf edge or an object's {type, _} field references.
  • Refinement schema — a predicate over an object's field-values; the extra constraint a refinement type adds on top of its base instance-type (e.g. a Post is a Note whose :title is a non-empty string).

Scope

Substrate side only — everything under next/**. The host-side adapters (lib/host/fed_sx_outbox.sx, lib/host/fed_sx_inbox.sx) are a deliberate follow-up that consumes this branch's public surface (DefineType / SubtypeOf verbs, peer_types, the /types/<cid> route) once loops/host's metamodel settles. This loop does not touch lib/host/.

Steps

Step 1 — DefineType + SubtypeOf genesis activity-types — DONE

New DefineActivity-form genesis files, parsed as data by bootstrap.erl at startup (no kernel change yet):

  • next/genesis/activity-types/define_type.sx — declares the DefineType verb. :schema accepts an activity whose :object carries a string :name and an optional list :fields.
  • next/genesis/activity-types/subtype_of.sx — declares the SubtypeOf verb. :schema accepts an :object carrying both :child-type-cid and :parent-type-cid as strings.

Schema bodies are SX source written with nested get (not keyword-threading) so they are directly evaluatable: keywords are not callable getters in the kernel and (-> d :k) does not get. Both are registered in next/genesis/manifest.sx (activity-types now 7) and the bundle counts in the bootstrap suites were bumped accordingly.

Tests: next/tests/define_type.sh, next/tests/subtype_of.sh — parse shape, schema accept/reject, and a term_codec envelope round-trip.

Step 2 — peer_types.erl receiver-side cache — DONE

next/kernel/peer_types.erl, a mirror of peer_actors.erl keyed by type CID. State [{TypeCidBytes, TypeRecord}, ...]. Pure API (new/2-threaded lookup/store/evict/types/lookup_or_fetch) plus a registered gen_server (put, lookup, state_for, known_types, lookup_or_fetch). On a miss lookup_or_fetch pulls a Cfg-supplied type_fetch_fn :: fun ((TypeCid, Cfg) -> {ok, Bytes} | {error, _}), decodes the wire bytes via term_codec, and caches the record. No fn → {error, no_fetch_fn}; fetch error or bad bytes do not poison the cache. Test: next/tests/peer_types.sh.

Step 3 — /types/<cid> route + discovery_type_fetch.erl — TODO

http_server.erl serves GET /types/<cid> with Accept: application/vnd.fed-sx.type-doc: the cached TypeRecord term_codec-encoded, 404 if not cached. discovery_type_fetch.erl holds the live-HTTP closure that peer_types:lookup_or_fetch calls. Tests: next/tests/peer_types_route.sh, next/tests/discovery_type_fetch.sh.

Step 4 — object-schema validation stage in pipeline.erl — TODO

A new apply_object_schema/2 stage between activity-type validation and the kernel append. When an inbound object carries {type, TypeName}, resolve the TypeRecord (local Define-name index → CID → peer_types:lookup_or_fetch) and apply its refinement schema to the object's field-values. Default strict_object_schema = false: an unresolvable type is let through with a validation_skipped log; opt-in strict mode rejects. Test: next/tests/object_schema.sh.

Out of scope (deliberately)

  • Host-side outbox/inbox adapters (lib/host/**).
  • Type evolution / version migration — schemas are immutable per CID; the "name → currently-valid CID" routing layer is a separate problem.
  • Subtype-of unification / rendering across nodes — the graph data lands via SubtypeOf activities; dedup/display is a consumer concern.

What the host-side adapter loop gets

Once all four steps land, the follow-up loops/host adapter work can treat the following as stable public surface:

  • DefineType / SubtypeOf activity verbs (publish a type, link two).
  • peer_types gen_server (cache a peer's type, look it up).
  • GET /types/<cid> (serve a type the node knows).
  • pipeline's object-schema stage (inbound objects validated against their declared refinement type when resolvable).