fed-sx-m2: Step 6c — auto-Accept on Follow ingestion + 9 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 37s

Per design §13.2 the v2 Follow policy is open-world: every
successfully-ingested Follow triggers an Accept publish from the
target actor. Enabled per-Cfg via {auto_accept_follows, true} so
manual-moderation deployments can leave it off; default off.

http_server.erl run_inbox_pipeline gained maybe_auto_accept/3:

  maybe_auto_accept(TargetAtom, Activity, Cfg) ->
      case field(auto_accept_follows, Cfg) of
          true ->
              case envelope:get_field(type, Activity) of
                  {ok, follow} ->
                      Req = [{type, accept}, {object, Activity}],
                      nx_kernel:publish_to(TargetAtom, Req);
                  _ -> ok
              end;
          _ -> ok
      end.

The publish routes through the full outbox pipeline (envelope
construct + HMAC sign + log append + outbox projection broadcast).
When the target's outbox :projections list shares the same
follower_graph projection that inbox broadcasts into, the bilateral
relationship fold-converges automatically — alice.followers = [bob]
and bob.following = [alice], both pending lists clear. No extra
test scaffolding needed because outbox:publish already runs the
broadcast hook from Step 7c.

Bad-sig and non-Follow ingestion short-circuit before the Accept
attempt (the validation pipeline rejects before run_inbox_pipeline's
ok branch fires).

9/9 in next/tests/auto_accept.sh:
  - auto_accept on: alice's outbox tip advances to 1
  - alice's outbox entry has :type = accept
  - follower_graph converges to {alice.followers=[bob],
    bob.following=[alice]}
  - both sides' pending lists clear after the Accept fold
  - auto_accept off (default): outbox stays empty; pending_inbound
    still gets populated from the Step 6b inbox-projection path,
    but alice.followers stays empty until human moderation acts
  - non-Follow ingestion (Create{Note}) with auto_accept on: no
    Accept published
  - bad-sig Follow with auto_accept on: no Accept (sig short-circuit
    in pipeline before maybe_auto_accept runs)

Step 6 fully closed (6a follower_graph projection, 6b inbox -> projection
broadcast wiring, 6c auto-Accept publish).

Conformance 761/761. 89/89 across 7 Step-6-adjacent suites
(inbox, inbox_peer_resolution, follower_graph, follow_lifecycle,
auto_accept, http_publish, nx_kernel_multi).
This commit is contained in:
2026-06-06 22:46:52 +00:00
parent 1d83120918
commit ee8a396ccd
3 changed files with 193 additions and 7 deletions

View File

@@ -1103,12 +1103,38 @@ run_inbox_pipeline(TargetAtom, Activity, PeerAS, InboxLog, Cfg) ->
ok ->
nx_kernel:append_inbox(TargetAtom, Activity),
broadcast_to_inbox_projections(Activity, Cfg),
maybe_auto_accept(TargetAtom, Activity, Cfg),
actor_inbox_post_response();
{error, bad_signature} -> unauthorized_response();
{error, no_signature} -> unauthorized_response();
{error, _} -> validation_failed_response()
end.
%% maybe_auto_accept/3 — Step 6c. Per design §13.2 the v2 default
%% Follow policy is open-world: every successfully-ingested Follow
%% triggers an Accept publish from the target actor. Enabled per-Cfg
%% via `{auto_accept_follows, true}` so callers that prefer manual
%% moderation can leave it off (manual moderation queue is v3).
%%
%% The Accept's `:object` is the original Follow envelope as
%% received — peers will use that to identify which Follow was
%% accepted. The publish goes through nx_kernel:publish_to/2 which
%% routes through the full outbox pipeline (construct + sign + log
%% + projection broadcast), so the target's outbox projections see
%% the Accept too.
maybe_auto_accept(TargetAtom, Activity, Cfg) ->
case field(auto_accept_follows, Cfg) of
true ->
case envelope:get_field(type, Activity) of
{ok, follow} ->
AcceptRequest = [{type, accept}, {object, Activity}],
nx_kernel:publish_to(TargetAtom, AcceptRequest);
_ -> ok
end;
_ -> ok
end.
%% broadcast_to_inbox_projections/2 — Step 6b. Cfg may carry
%% `{inbox_projections, [Name, ...]}` listing projection gen_servers
%% that should see every successfully-ingested inbound activity.