fed-sx-m2: Step 4a — per-actor HTTP sub-paths + 17 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 30s

Per design §16.1 each actor has /outbox /inbox /followers /following
sub-paths. New split_first_slash/1 helper lets the GET /actors/...
dispatch arm fan out on the sub-segment:

  GET  /actors/<id>            actor doc (M1 — unchanged)
  GET  /actors/<id>/outbox     outbox stub (4a)
  GET  /actors/<id>/inbox      inbox stub (4a)
  GET  /actors/<id>/followers  follower stub (4a)
  GET  /actors/<id>/following  following stub (4a)
  POST /actors/<id>/inbox      202 Accepted stub (4a; Step 5 real)

Four new content-negotiated response functions mirror the existing
actor_doc_response_for/2 shape (text / json / activity_json / sx
variants):

  actor_outbox_response_for/2
  actor_inbox_get_response_for/2
  actor_followers_response_for/2
  actor_following_response_for/2

POST returns 202 via new accepted_response/1 +
actor_inbox_post_response/0.

Unknown sub-paths under /actors/<id>/ return 404. Bare /actors/<id>
preserves the M1 actor-doc arm so http_route + http_post_format
regression suites stay green.

4b-4e (token map, route/3 kernel access, per-actor outbox listing
from log entries, real inbox pipeline) layer on top of this dispatch
in subsequent iterations.

17/17 in next/tests/http_multi_actor.sh covering:
  - split_first_slash sanity (no slash / id+sub / trailing slash)
  - all four GET sub-paths return 200 with stub bodies
  - POST inbox returns 202 + 'accepted'
  - unknown sub-paths return 404 (GET and POST)
  - empty /actors/ returns 404
  - body carries the actor id
  - content negotiation: outbox JSON, inbox SX, followers JSON

Conformance 761/761. 120/120 across 10 Step-4-adjacent suites
(http_route, http_publish, http_post_format, http_marshal,
http_publish_fold, http_listen_bif, http_server_start,
nx_kernel_multi, actor_state_pure, bootstrap_start).
This commit is contained in:
2026-06-06 13:47:00 +00:00
parent 238a1fbea0
commit 0b8772ec69
3 changed files with 365 additions and 19 deletions

View File

@@ -260,21 +260,35 @@ token; the token now maps to an `:actor_id` rather than a fixed `alice`.
**Deliverables:**
- New route prefixes: `/actors/<id>/inbox`, `/actors/<id>/followers`,
`/actors/<id>/following`.
- `http_server:route/3` (Cfg → Cfg+Kernel) so handlers can look up
actor state.
- Cfg's `:publish_token` becomes `:tokens => #{Token => ActorId}` map.
- `cid_response_for/2` already format-aware; per-actor outbox listing
uses the same machinery.
**Tests:**
- GET /actors/alice → 200 with actor doc.
- GET /actors/unknown → 404.
- POST /activity with alice's token publishes to alice.
- POST /activity with bob's token publishes to bob.
- Two actors' outboxes are independent.
- [x] **4a** — Per-actor URL routing. New `split_first_slash/1`
helper splits the `/actors/` suffix into `{Id, SubPath}`.
GET dispatch routes `outbox` / `inbox` / `followers` / `following`
sub-paths to four new content-negotiated response functions
(`actor_outbox_response_for/2`, `actor_inbox_get_response_for/2`,
`actor_followers_response_for/2`,
`actor_following_response_for/2`) — text / json / activity_json /
sx variants per existing format pattern. POST dispatch routes
`inbox` to a 202 Accepted stub (`actor_inbox_post_response/0` +
`accepted_response/1`). Unknown sub-paths under `/actors/<id>/`
return 404. Bare `/actors/<id>` keeps the M1 `actor_doc_response_for`
arm. 17 cases in `http_multi_actor.sh`.
- [ ] **4b** — Token → ActorId map. Cfg's `:publish_token` becomes
`:tokens` (proplist `[{Token, ActorId}, ...]`). POST /activity
resolves the bearer token to an actor id and routes through
`nx_kernel:publish_to/2` instead of `publish/1`. Multi-token
Cfg keeps the M1 `:publish_token` single-token field as a
back-compat alias for one token mapping to `alice`.
- [ ] **4c** — `http_server:route/3(Req, Cfg, Kernel)` — the Cfg
carries opaque `:kernel` reference (or accepts the registered
`nx_kernel` atom) so per-actor handlers can call
`nx_kernel:state_for/1`, `actor_log_state/2`, projections etc.
- [ ] **4d** — Per-actor outbox listing reads from the named
bucket's log entries via `nx_kernel:actor_log_state/2`, content-
negotiates as today (text / json / sx). `?page=N` pagination
layered on top using `log:replay/3`.
- [ ] **4e** — POST /actors/<id>/inbox stays a 202 stub for 4a-4d.
Step 5 lands the real ingestion pipeline (sig verify + inbox-
bucket append + projection broadcast).
**Acceptance:** `bash next/tests/http_multi_actor.sh` passes 14+ cases.
@@ -717,6 +731,22 @@ proceed.
Newest first.
- **2026-06-06** — Step 4a: per-actor HTTP sub-paths. New
`split_first_slash/1` helper lets GET / POST `/actors/<id>/...`
paths route on the sub-segment (`outbox`, `inbox`, `followers`,
`following`). Four new content-negotiated response stubs
(`actor_outbox_response_for/2`, `actor_inbox_get_response_for/2`,
`actor_followers_response_for/2`, `actor_following_response_for/2`)
with text / json / activity_json / sx variants, mirroring the
existing `actor_doc_response_for/2` shape. POST
`/actors/<id>/inbox` returns a 202 Accepted stub
(`actor_inbox_post_response/0` + `accepted_response/1`); real
ingestion pipeline lands in Step 5. Unknown sub-paths return
404. Bare `/actors/<id>` keeps the M1 actor-doc arm intact —
`http_route` and `http_post_format` regression suites unchanged
(10/10 each). 17/17 in `http_multi_actor.sh`. Conformance
761/761 preserved. 120/120 across 10 Step-4-adjacent suites.
- **2026-06-06** — Step 3 (closes Step 3): key rotation via Update.
`actor_state.erl` `fold_update` routes patches through
`apply_patch/3` which special-cases `{add_publicKey, KeyProplist}`