Approved posts may carry mediaAssetIds and altTexts since the repository
gate was lifted, but the scheduler built connectors without an asset
loader, so Mastodon and Telegram rejected every post with media as
INVALID_POST and alt texts never reached them.
- media.ts: loadAsset reads media_assets inside the execution's tenant
(app.workspace_id, RLS forced); openAsset fetches the sealed object,
opens the SPENC1 frame with S3_KEK and checks the content hash.
Read-only; bytes go worker to provider and never through the API.
- preparePostForDispatch maps positional altTexts onto
providerMetadata.altText keyed by asset id.
- Instagram joins the scheduler registry so its posts fail with an
explicit connector error instead of UnknownProviderError.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Instagram connector existed but was never registered, so Channels showed
it as "provider unavailable" and publishing could not resolve it.
- Register createInstagramConnector in the connections registry and the
publishing registry; add the connector-runtime publishing policy
(idempotency "none": media_publish has no key, never replay).
- The Facebook app credentials identify the Hub, not a collective: read them
only from INSTAGRAM_CLIENT_ID / INSTAGRAM_CLIENT_SECRET. Drop the
clientId/clientSecret connect fields and stop copying the app secret into
each connection's vault entry. The provider is connectable only when both
are set (connectEnabled + connectNote).
- Fail the connect when several Instagram accounts are granted instead of
silently publishing as the first Page's account.
- Fix the connector package's pre-existing lint errors (it now ships in api).
- Tests: contract cases for env-only credentials and the multi-account
refusal; connections integration case for provider gating and the
Facebook dialog redirect.
- docs/oauth-connect.md: Instagram setup, callback URI and limits.
Not in this change: publishing images needs a public plaintext JPEG URL that
Meta downloads, and storage is client-side encrypted, so presigned S3 URLs
cannot serve it. Until a short-lived media endpoint exists, publishing to
Instagram fails with an explicit error. Token refresh via ig_refresh_token
on graph.facebook.com also needs checking against Facebook Login tokens.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Self-hosted multi-platform broadcast newsroom for activist collectives:
publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style
column wall with hostile-content-safe rendering, live control room with Auto
Director, bridged chat governance with polls and quorum, distributed sandboxed
transcode workers, encrypted content-addressed archive, monthly analytics.
MIT licensed. See README.md and docs/.