Skip to content

Add Post_Types projector; pivot onboarding SDD to direct AP option writes#31

Draft
kraftbj wants to merge 9 commits intotrunkfrom
post-type-sync-DOTCOM-16875
Draft

Add Post_Types projector; pivot onboarding SDD to direct AP option writes#31
kraftbj wants to merge 9 commits intotrunkfrom
post-type-sync-DOTCOM-16875

Conversation

@kraftbj
Copy link
Copy Markdown
Contributor

@kraftbj kraftbj commented Apr 24, 2026

Fixes DOTCOM-16875

Summary

Two linked changes around the "who owns the AP option" question:

  1. New Automattic\Fosse\Post_Types projector (src/class-post-types.php) reads AP's stored activitypub_support_post_types and feeds it into Atmosphere's atmosphere_syncable_post_types filter. A user ticks a post type once in AP's settings; it federates to Mastodon and Bluesky. One-way, no FOSSE-owned option.

  2. Onboarding SDD amendment (sdd/onboarding-setup-ux/). The merged spec (PR SDD: onboarding-setup-ux (requirements + spec + plan) #25) planned fosse_ap_actor_mode / fosse_ap_support_post_types options projected into AP via pre_option_* filters. Superseded by the direct-write approach: FOSSE's Setup page writes straight to activitypub_actor_mode / activitypub_support_post_types. AP's admin screen keeps editing the same keys — single source of truth, no divergence.

Why the pivot

Original plan for DOTCOM-16875 was a FOSSE-owned fosse_syncable_post_types option projected into both AP and AT via filters, symmetric with Object_Type. Landed Automattic/wordpress-activitypub#3218 to add a dedicated AP filter for that.

AP maintainer pushed back: the stock option_activitypub_support_post_types filter already exists, add_post_type_support() covers adds, so a new filter isn't warranted. Fair point — and it made the core issue obvious. Any read-time projection (whether a dedicated filter or the stock option_*/pre_option_* hooks) silently overrides AP's admin UI: user toggles a checkbox, projection returns something else, admin becomes a lie. Two sources of truth, worst version.

New direction: AP's option is canonical. One-way projection into AT only. AP PR closed.

Divergence from the Object_Type pattern is deliberate — noted in the class docblock. Object-type semantics are FOSSE-specific (force short-form everywhere vs defer); post-type selection is not — it's exactly what AP already stores. Same-shape data, reuse the store.

Changes

  • src/class-post-types.php — new projector class. Reads activitypub_support_post_types, returns it from atmosphere_syncable_post_types. Falls back to ['post'] on missing/corrupted option.
  • fosse.php — new init action that calls Post_Types::register() behind the same class_exists guard used for Object_Type.
  • tests/php/Post_TypesTest.php — six tests: default on unset option, value returned when set, empty array preserved (don't resurrect federation the user disabled), upstream default discarded, non-array option falls back to default, register() idempotent.
  • sdd/post-type-sync/notes.md — SDD fix record (problem, approach, tasks, decision trail).
  • sdd/onboarding-setup-ux/*.md — spec / plan / requirements / planned-decisions amended. fosse_ap_* option plan replaced with direct activitypub_* writes.

Test plan

  • composer run-script lint-php clean
  • composer run-script test-php — 19/19 pass (6 new)
  • pnpm run format:check clean
  • Manual: unset activitypub_support_post_types, confirm Atmosphere sees ['post']
  • Manual: set activitypub_support_post_types to ['post', 'page'], confirm Atmosphere's filter returns the same
  • Manual: uncheck all post types in AP admin, confirm Atmosphere syncs nothing (empty array preserved, no silent fallback)

kraftbj added 2 commits April 24, 2026 11:21
…ypes

Projects AP's stored `activitypub_support_post_types` option into
Atmosphere's `atmosphere_syncable_post_types` filter, so the post types
a user ticks in AP's settings also federate to Bluesky without a second
configuration step.

One-way by design. Unlike `Object_Type` — which owns `fosse_object_type`
because short-form-vs-WP-post-format is a FOSSE-specific discriminator —
post-type selection has no FOSSE-specific semantics. It's exactly what
AP already stores, so reusing AP's option avoids a second source of
truth that would silently override AP's admin UI on read. The class
docblock notes the asymmetry so the pattern isn't reflexively "fixed"
later.

Registered from fosse.php inside an `init` action with the same
`class_exists` guard used for `Object_Type`, so a bare clone without
vendor/ still loads the bundled backends without fataling.

See DOTCOM-16875. Companion SDD notes at sdd/post-type-sync/.
Flips the "AP settings ownership" decision recorded in PR #25. Original
plan was FOSSE-owned `fosse_ap_actor_mode` / `fosse_ap_support_post_types`
options projected into AP via `pre_option_*` filters at read time. That
silently overrides AP's admin UI — a user toggles a checkbox, FOSSE's
filter returns something else on read, admin becomes a lie.

The upstream PR thread on Automattic/wordpress-activitypub#3218 made
the divergence concrete: `option_activitypub_support_post_types`
already exists, which is what a `pre_option_*` projection would ride
on, and that's precisely the silent-override mechanism. Single source
of truth (AP's option) + direct writes from both surfaces is the
clean fix.

AP_Provider now writes `activitypub_actor_mode` and
`activitypub_support_post_types` with `update_option()` and registers
no `pre_option_*` filters. Cross-network post-type sync into Atmosphere
is handled separately by `Automattic\Fosse\Post_Types` (DOTCOM-16875).

See DOTCOM-16875.
Copilot AI review requested due to automatic review settings April 24, 2026 16:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new FOSSE “Post_Types” projector to make ActivityPub’s post-type allowlist the single source of truth and project it into Atmosphere, and updates the onboarding SDD to reflect the pivot away from fosse_ap_* option projection toward direct activitypub_* option writes.

Changes:

  • Introduce Automattic\Fosse\Post_Types to feed activitypub_support_post_types into atmosphere_syncable_post_types (with sane defaults / corruption handling).
  • Register the new projector from fosse.php alongside the existing Object_Type registration guard.
  • Update onboarding SDD docs (spec/plan/requirements/planned-decisions) and add a decision-trail note doc for the ownership pivot.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/class-post-types.php Adds the post-type projector that sources AP’s option and returns it for Atmosphere’s filter.
fosse.php Registers the new projector on init behind a class_exists guard.
tests/php/Post_TypesTest.php Adds unit tests for defaulting, passthrough, empty array behavior, and registration behavior.
sdd/post-type-sync/notes.md Records the decision trail and implementation approach for the ownership pivot + projection.
sdd/onboarding-setup-ux/spec.md Updates the spec from pre_option_* projection to direct writes to AP options + one-way AT projection.
sdd/onboarding-setup-ux/requirements.md Revises the resolved “AP settings ownership” decision to direct activitypub_* writes.
sdd/onboarding-setup-ux/planned-decisions.md Documents the superseded projection plan and the rationale for the direct-write pivot.
sdd/onboarding-setup-ux/plan.md Updates implementation tasks to write activitypub_* directly and removes pre_option_* projection steps.

Comment thread sdd/post-type-sync/notes.md Outdated
Comment thread tests/php/Post_TypesTest.php
Comment thread tests/php/Post_TypesTest.php Outdated
Comment thread sdd/post-type-sync/notes.md
@kraftbj
Copy link
Copy Markdown
Contributor Author

kraftbj commented Apr 24, 2026

@RCowles FYI on the SDD amendment.

kraftbj added 3 commits April 24, 2026 11:37
Without this, an Atmosphere-only site (no ActivityPub) gets
its atmosphere_syncable_post_types filter overridden with an
invented ['post'] default — the projector has no source of
truth to project when AP isn't loaded.
@kraftbj kraftbj marked this pull request as draft April 24, 2026 19:50
@kraftbj
Copy link
Copy Markdown
Contributor Author

kraftbj commented Apr 24, 2026

Converting to draft: Codex's adversarial review surfaced a high-severity rollback hazard in the downstream Atmosphere path (narrowing activitypub_support_post_types would orphan Bluesky records for already-synced posts of the removed types, because Atmosphere's on_status_change and on_before_delete gate cleanup on the same allowlist used for publish eligibility).

The projector in this PR is correct; the bug lives in Atmosphere and is fixed upstream at Automattic/wordpress-atmosphere#38 (split the publish-time and cleanup-time gates, three PHPUnit cases added).

Parking this PR in draft until that lands. Follow-up work (bundled re-sync, FOSSE-side regression test, taking this PR out of draft) tracked at DOTCOM-16909. Decision trail captured in sdd/post-type-sync/notes.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants