fed-sx-m2: Step 1a — nx_kernel per-actor bucket refactor + 17 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 20s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 20s
State shape becomes [{actors, [{Id, Bucket}, ...]}, {next_actor_seq, N}]
with ActorBucket = [{key_spec, KS}, {actor_state, AS}, {log, L},
{projections, [Name]}, {next_published, N}]. Pure-functional multi-
actor APIs (new/0, add_actor/4, has_actor/2, actors/1, actor_count/1,
publish/3, per-actor accessors, with_actor_projections/3) join the
legacy single-actor accessors, which now read from the first bucket.
Every M1 test continues to pass via bootstrap:start/3 -> new/3 ->
first-bucket lookup.
Local has_keyed/find_keyed/set_keyed/set_bucket helpers cover the
keyed-list ops since lists:keymember/keyfind aren't registered in
this substrate.
next/tests/nx_kernel_multi.sh 17/17. M1 nx_kernel-adjacent suites
green (bootstrap_start 10/10, nx_kernel_server 11/11, http_publish
10/10, smoke_app_pure 12/12, http_post_format 13/13, http_publish_fold
10/10, http_marshal 10/10). Erlang conformance 761/761 preserved.
Blockers entry added for pre-existing http_server_tcp.sh 0/5
regression (78eae9ef left dead helper references in runtime.sx:1593) —
substrate-side, out of m2 scope, confirmed pre-existing by reverting
1a's changes and re-running.
This commit is contained in:
@@ -115,36 +115,31 @@ actors.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
```erlang
|
||||
%% nx_kernel state shape becomes:
|
||||
%% [{actors, [{ActorId, ActorBucket}, ...]},
|
||||
%% {next_actor_seq, NextN}]
|
||||
%%
|
||||
%% ActorBucket = [{key_spec, KS}, {actor_state, AS},
|
||||
%% {log, LogState}, {projections, [Name]},
|
||||
%% {next_published, NextSeq}]
|
||||
|
||||
-export([new/0, add_actor/4, has_actor/2,
|
||||
publish/2, publish/3, %% /2 = first actor only
|
||||
actor_log_tip/2, actor_state/2, ...]).
|
||||
|
||||
new() -> [{actors, []}, {next_actor_seq, 1}].
|
||||
add_actor(ActorId, KeySpec, AS, State) -> {ok, NewState}.
|
||||
publish(ActorId, Request, State) -> ... %% per-actor
|
||||
```
|
||||
|
||||
`bootstrap:start/3` continues to work — it adds one actor named `alice`
|
||||
to a fresh kernel — preserving every M1 test that uses the
|
||||
single-actor entry point.
|
||||
|
||||
**Tests:**
|
||||
|
||||
- New kernel has no actors.
|
||||
- add_actor + has_actor round-trip.
|
||||
- Two actors maintain independent logs + sequences.
|
||||
- publish/3 advances only the named actor's bucket.
|
||||
- Concurrent gen_server-mediated publishes for different actors don't
|
||||
serialise.
|
||||
- [x] **1a** — Pure-functional bucket APIs. State shape becomes
|
||||
`[{actors, [{ActorId, ActorBucket}, ...]}, {next_actor_seq, N}]`
|
||||
with `ActorBucket = [{key_spec, KS}, {actor_state, AS}, {log, L},
|
||||
{projections, [Name]}, {next_published, N}]`. New exports: `new/0`,
|
||||
`add_actor/4`, `has_actor/2`, `actors/1`, `actor_count/1`,
|
||||
`next_actor_seq/1`, `actor_bucket/2`, `publish/3`, per-actor
|
||||
accessors (`actor_log_state/2`, `actor_log_tip/2`, `actor_key_spec/2`,
|
||||
`actor_state/2`, `actor_projections/2`, `actor_next_published/2`),
|
||||
`with_actor_projections/3`. Legacy single-actor accessors
|
||||
(`actor_id/1`, `key_spec/1`, `actor_state/1`, `log_state/1`,
|
||||
`log_tip/1`, `projections/1`, `next_published/1`,
|
||||
`with_projections/2`, legacy `publish/2`) continue to read from the
|
||||
first bucket — every M1 test passes via `bootstrap:start/3` →
|
||||
`new/3` → first-bucket lookup. `lists:keymember`/`keyfind` not in
|
||||
the substrate; local `has_keyed`/`find_keyed`/`set_keyed`/
|
||||
`set_bucket` helpers handle the keyed-list ops.
|
||||
`next/tests/nx_kernel_multi.sh` 17/17.
|
||||
- [ ] **1b** — Multi-actor gen_server. `start_link/3` still works as
|
||||
the single-actor entry; add `add_actor/3` (gen_server call,
|
||||
bumps bucket), `publish_to/2(ActorId, Request)`, `log_tip_for/1`,
|
||||
`actors/0`, `state_for/1`, `with_projections_for/2`. Existing
|
||||
`publish/1`/`log_tip/0`/etc route through bucket-0 unchanged.
|
||||
Concurrent publishes to distinct actors don't serialise across the
|
||||
mailbox (multiple casts queued before each is processed). New tests
|
||||
extend `nx_kernel_multi.sh` with 6-8 gen_server-mediated cases.
|
||||
|
||||
**Acceptance:** `bash next/tests/nx_kernel_multi.sh` passes 12+ cases.
|
||||
|
||||
@@ -650,3 +645,48 @@ Things still under-specified; resolve as work begins.
|
||||
via /inbox, does A keep B's signed envelope verbatim (for re-broadcast
|
||||
on Announce), or does A re-construct + re-sign with A's own key?
|
||||
AP-canon: keep verbatim. Confirm at Step 5.
|
||||
|
||||
---
|
||||
|
||||
## Blockers
|
||||
|
||||
Pre-existing regressions inherited from the M1 closeout. Out of m2
|
||||
scope (substrate, not `next/**`), tracked here so iteration can
|
||||
proceed.
|
||||
|
||||
1. **`next/tests/http_server_tcp.sh` 0/5** — pre-existing regression
|
||||
introduced by `78eae9ef` (`fed-sx-m1: 8b-bridge cleanup`).
|
||||
`lib/erlang/runtime.sx:1593` still references `er-http-resp-to-sx`
|
||||
and `er-http-req-of-sx` in `er-bif-http-listen`'s sx-handler body,
|
||||
but the cleanup commit removed both helpers without rewriting the
|
||||
BIF. Listener binds (TCP socket accepts), but every request handler
|
||||
crashes on first call to the undefined helpers — curl gets 000 /
|
||||
empty body. Fix needs to rewrite the sx-handler body around the
|
||||
live `er-request-dict-to-proplist` / `er-proplist-to-dict`
|
||||
helpers (which the cleanup commit's message claimed are already
|
||||
in use, but which the BIF body never picked up). Substrate work,
|
||||
belongs on `loops/erlang`. m2 work continues against the in-process
|
||||
HTTP layer (`http_marshal.sh` 10/10, `http_publish_fold.sh` 10/10)
|
||||
until resolved. Confirmed pre-existing by stashing 1a's changes and
|
||||
re-running on the unmodified m1 closeout HEAD.
|
||||
|
||||
---
|
||||
|
||||
## Progress log
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-06-06** — Step 1a: per-actor bucket refactor of `nx_kernel`.
|
||||
State shape now `[{actors, [{Id, Bucket}, …]}, {next_actor_seq, N}]`;
|
||||
added pure-functional multi-actor APIs (`new/0`, `add_actor/4`,
|
||||
`has_actor/2`, `actors/1`, `publish/3`, per-actor accessors,
|
||||
`with_actor_projections/3`). Legacy single-actor accessors
|
||||
preserved as bucket-0 lookups so every M1 test continues to
|
||||
pass via `bootstrap:start/3` → `new/3` → first-bucket read.
|
||||
Local `has_keyed`/`find_keyed`/`set_keyed`/`set_bucket` helpers
|
||||
cover the keyed-list ops since `lists:keymember`/`keyfind` aren't
|
||||
registered in this substrate. New test suite
|
||||
`next/tests/nx_kernel_multi.sh` 17/17; all M1 nx_kernel-adjacent
|
||||
suites green (`bootstrap_start`, `nx_kernel_server`, `http_publish`,
|
||||
`smoke_app_pure`, `http_post_format`, `http_publish_fold`,
|
||||
`http_marshal`). Erlang conformance 761/761 preserved.
|
||||
|
||||
Reference in New Issue
Block a user