The header double-rendered 'Tactical Media Broadcast Hub': white via the
Logo lockup's wordmark, then again in red via the accent span. The mark
alone + the red span is the whole lockup the palette calls for.
OKLCH-based: any computed color with hue 200–300° and chroma > 0.006 on
/chat or /files/drive (both iframes included) fails the check. Run after
Element/oCIS image bumps; PLAYWRIGHT_PATH can point at an existing
node_modules. Found by the branding panel; threshold from the brand spec.
S9: boost draft (providerMetadata.sourceRemoteRef) → immediate-rule approve
→ POST /publishing/drafts/:id/amplify { connectionId, kind: repost } →
verify the source status reblogged on Mastodon. ONLY=S9 runs it standalone.
Gap list updated: boost + Temporal-queue + status-read gaps closed
(auto-publish remains a governance-model decision, not a missing route).
The oCIS web fetches the OIDC discovery document from the Hub issuer in the
browser — connect-src only allowed same-origin + blob, so the fetch was
blocked and the web fell back to its own login. With the CSP fix + the
external issuer flip, the full SSO chain works: Hub login -> authorize ->
consent SPA -> code -> autoprovisioned personal drive.
createPublishingCredentialAccessor is execution-fenced (Temporal contexts
only) — the API-process amplify route threw EXECUTION_CREDENTIAL_FENCE.
Use the established PgConnectionStore+vault accessor instead (same trust
level as the archive amplify route's bot-token path).
POST /publishing/drafts/:draftId/amplify { connectionId, kind?: repost|quote }:
the governance gate is the draft state (only approved drafts amplify), the
target is providerMetadata.sourceRemoteRef recorded at creation — never a
caller-supplied id. Connectors resolve from a process-level publishing
registry (vault-backed credentials); capability-checked per kind. Closes
the gap the governance sim documented (boosts fell back to replies).
Panel consensus (the branding panel): don't mount full-app iframes on
mobile — nested scrolling, keyboard collapse and double chrome break both
Element and oCIS under the bottom tab bar. Chat and Drive render a gateway
card (same-tab handoff, matrix: deep link, signed-in-as) below 1024px; the
iframe stays on desktop. hub-sso.html pins mx_local_settings.theme to
custom-OccupyHub Dark once (version-flagged) — a device's earlier picker
choice would otherwise beat config.json's default_theme.
oCIS compresses the idp sign-in HTML, and sub_filter cannot rewrite
compressed bodies. Works on the grey/failover path where the edge serves
files; in tunnel mode files bypasses the edge entirely (tunnel ingress
points straight at oCIS), so the permanent brand fix remains the Hub OIDC
issuer (docs/design/2026-10-13-files-oidc-sso.md).
The sign-in page is served by oCIS's idp service, which the web theme.json
cannot touch. Inject hub-signin.css via sub_filter on /signin/ until oCIS
sits behind the Hub OIDC issuer (see docs/design/2026-10-13-files-oidc-sso.md).
Phase 1 kills the navy login wall (provider + PKCE + auto-consent for the
first-party oCIS web client); phases 2-3 move uploads into personal drives
and share collective folders into them. Mirrors the Matrix JWT broker: the
Hub is the identity, oCIS is a relying party.
Hero strip (ES/EN): 'Not a platform. A process.' / 'Decide together.
Publish anywhere. Forget nothing.' / 'What they delete, we archive. What
they silence, we broadcast.' Footer line: 'Not a product. A process.
Built by collectives, for collectives.'
From the brand review: the sidebar truncated 'Tactical Media Broadcast Hub'
on eleven desktop routes; unknown routes rendered a stock white Next.js 404;
solo users saw the raw 'groupid must be a UUID' validation text on Files;
Element's config brand string still read 'OccupyMedia Hub'.
Inline [appservice.*] tables drop the namespaces field (registration then
fails M_EXCLUSIVE for every AS user). The env var points tuwunel at the
/appservices mount (telegram + hub YAMLs, both with namespaces).
W1's governance sim found approved publishes never executing: the api starts
workflows on tmbh-publishing while the 3-day-old scheduler image consumed the
old superposter-publishing default. Pin TEMPORAL_TASK_QUEUE on both services.
The live tuwunel does not offer m.login.jwt (the jwt.* flat config keys were
inert), so the JWT broker flow could never work. Pivot: appservice.hub owns
the exclusive hub_* namespace on the homeserver; POST /matrix/session now
registers @hub_<username> with the as_token and mints a single-use
m.login.token via login/get_token (?user_id= impersonation). Optional
MATRIX_SSO_HS_TOKEN authenticates inbound appservice transactions, acked by
the new MatrixAppserviceController sink. Response shape unchanged.
- group-files: origin filter facet; GET /files/:id returns 410 for unavailable
rows after the ACL recheck; fix latent group_members.status filter and unbound
workspace parameter that would 500 listFiles
- archive-bot: markRedacted revokes live group_file_shares rows in-transaction
- new live-DB integration suite for the archive index surface