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
- archive_sync_state keyed by room per migration 029 (drop synthetic id cursor)
- putStaging buffers the stream and sends content-length (oCIS rejects chunked)
- mimeClass passthrough from sniffed payload
- edge-firewall: RETURN docker-bridge ingress before the CF-range catch-all so
container egress (Matrix/R2/platform) survives the 80/443 source filter
- files scaffold: keep the ocdav data-gateway hop on-loopback
The docker build (fresh install, container @types resolution) fails on
http.test.ts's enhanced-Response mock (bytes/textStream) — tests are vitest
territory, never part of the dist build.
page.tsx now calls the real backend: GET /files with groupId/name/mimeClass/
cursor/limit (origin filter dropped — the api has no origin param), shares
tracked as ShareCreated (revoke by id), retention mapped to the orthogonal
legalHold model, downloads by item.name, samples reshaped to the wire
contract.
GroupFile gains mimeClass (the indexed coarse class the row icon and the
filter depend on): core contract, service row mapper, parseGroupFile guard,
test fixture, UI types — one vocabulary end to end. parseGroupFile's roomId
becomes null-tolerant to match direct-upload rows (mapping input stays
strict).
Verified: core build clean, api typecheck 0 errors + group-files 22/22,
web typecheck 0 errors.