Add a companion module initialization gate#3541
Conversation
|
Why not simply unhook all inbox handlers and hook in yours? |
|
Fair point. The first Bridge prototype did essentially that: keep the verified I introduced the earlier handoff to avoid coupling a companion to the growing I will verify both the shared and per-Actor Inbox paths against that approach. Thanks for pointing that out. |
4967e3e to
0f7c67b
Compare
|
Thanks, you are right. I verified that both REST controllers fire the existing Inbox actions after their permission callbacks, independently of I have now:
The force-pushed PR now contains only the module initialization gate. Its narrower purpose is to avoid depending on concrete initializer callbacks and exact priorities when a companion disables Handler, Scheduler, Router, or selected REST surfaces. The revised reference implementation is Axismundi ActivityPub Bridge 0.0.12 Alpha. |
|
A quick update from the staging integration: the signed S2S Follow/Accept path is now working end to end against mastodon.social in both directions. Verified paths:
The final issue found during this test was not in signature verification or the Inbox handoff. Axismundi deliberately keeps domain-ledger payloads free of JSON-LD representation concerns, but the Bridge initially submitted that context-free payload directly to transport. Mastodon accepted the HTTP request and then discarded it during asynchronous Activity processing because the ActivityStreams context was absent. The Bridge now finalizes outbound Activities through Object Projections before transport, restoring the intended ownership boundary: Activities owns domain state, Object Projections owns JSON-LD representation, and the official plugin owns protocol transport. The fix and regression coverage are in Jiwoon-Kim/axismundi@9b78ef5. The official plugin has understandably optimized for broad WordPress and Fediverse compatibility. Axismundi's URI-keyed Actor, Object, Activity, and relationship repositories optimize for a more extensible domain model and a block-theme-native Fediverse frontend. With the module gate, those goals compose cleanly rather than duplicating protocol behavior: the official plugin remains the interoperability and S2S layer, while a companion can replace selected domain and presentation layers. If you have time, I would really appreciate testing this reference composition or pointing out assumptions that would make it unsuitable upstream. The working staging surface is: Scope of the current E2E evidence is specifically Follow/Accept. Like, Undo, shared-Inbox delivery, and Create delivery remain separate activity-level scenarios. |
|
The updated companion releases used for the successful signed Follow/Accept E2E are now available:
These are the packaged versions corresponding to the staging result described above. The Bridge release includes the outbound Activity JSON-LD finalization fix; Activities includes Follow-cycle succession and Re-follow controls; Object Projections owns canonical ActivityStreams context assembly. |
|
Thanks for the quick turnaround on the inbox handoff, and for verifying both controller paths before removing it. The E2E work against mastodon.social is genuinely appreciated — that's more validation than most PRs bring. On the module gate itself, I'm going to pass, and I want to be transparent about why rather than just closing it. The core problem is API surface. This PR promotes ~35 internal module names ( There's also a support concern: a one-line filter that can switch off And I don't think you need the gate for your stated use case. What the Bridge actually needs is "the official type handlers must not act on activities the companion has claimed," and that's expressible today at the behavior level:
If you hit a specific behavior that can't be prevented or claimed through those — say, a handler with a side effect that needs a skip filter like the storage one — that's exactly the kind of small, targeted PR I'd be glad to take. "This behavior fired when the companion had already claimed the activity" is a concrete, testable contract; "this module didn't initialize" isn't. Same conclusion as on #3548, really: the composition keeps working precisely because the seams already exist. Let's keep growing those seams one verified behavior at a time instead of freezing the module map. |
|
Thanks for the detailed explanation. I agree with the behavior-level boundary and have removed the module-gate dependency from the companion. The Bridge now:
The only initializer still disabled is I verified the revised composition against both this fork and unmodified ActivityPub 9.0.2. Shared and per-Actor Inbox handling, unclaimed fallback storage, WebFinger, outbound signing, and Follow/Accept queueing all pass. The implementation and regression coverage are in Jiwoon-Kim/axismundi@ff959fe. This PR is no longer needed, so I am closing it. Thank you for steering this toward the smaller contract. |
Summary
This draft adds one backwards-compatible extension surface for companion plugins:
activitypub_module_enabled, an early gate around independently initialized runtime, REST, and admin modules.Every module remains enabled by default, so stock behavior is unchanged. A companion can retain the official protocol surfaces it needs while replacing selected presentation, lifecycle, or domain modules.
Why
As pfefferle pointed out, a new verified-Inbox handoff is not necessary. The existing REST controllers already fire
activitypub_inboxandactivitypub_inbox_sharedafter their permission callbacks, andactivitypub_skip_inbox_storagecan prevent duplicate CPT persistence.The remaining purpose of this PR is narrower: provide a supported, stable way to stop module initializers before they register callbacks. Without a gate, companion plugins must reach into concrete class names, callbacks, and exact priorities with
remove_action(). That is workable today, but silently becomes ineffective when an initializer or priority changes.For example, a companion with its own URI-keyed Activity and relationship repositories can disable
runtime.handlerandruntime.scheduler, retainruntime.signature,rest.server,rest.inbox, andrest.actors_inbox, then consume the existing Inbox actions. The official plugin remains responsible for request validation and transport while the companion owns domain state.This PR no longer adds or depends on a new Inbox handoff API. The previous handoff commit has been removed from the branch.
Reference implementation
Axismundi ActivityPub Bridge 0.0.12 Alpha uses the module gate together with the existing Inbox actions:
activitypub_skip_inbox_storageskipsap_inboxonly after Axismundi successfully claims the Activity; andThe surrounding alpha stack is available here:
The companion plugins and block theme provide local and remote Actor profile pages, Object and Activity views, social relationships, and federated-media presentation in the site's native frontend. Axismundi owns the URI-keyed domain and presentation layers; the official plugin remains the intended S2S transport and interoperability layer.
Staging references:
Validation
Refs #3533