Matrix gains emoji-list backed by MSC2545 image packs: room state
im.ponies.room_emotes (any state key) plus the personal
im.ponies.user_emotes account-data pack, sticker-only entries excluded,
identifiers are literal shortcodes (Matrix reactions send the annotation
key as-is; the mxc URL is exposed alongside). Discord emoji-list results
now ride the lifecycle-owned bounded entity cache, invalidated by
GuildEmojisUpdate; the non-privileged GuildExpressions intent is added so
that dispatch actually arrives. Google Chat custom-emoji listing is
documented as unavailable: customEmojis.list requires user auth while the
plugin is a chat.bot service-account channel.
* fix(matrix): guard malformed poll answers instead of throwing TypeError
parsePollStart mapped poll.answers with no runtime shape check, but
poll event content is sender-controlled JSON. A poll start event with
answers not an array, null entries, or non-string ids threw a
TypeError that bubbled through thread/reply context building to the
ingress top-level catch, silently dropping the whole message - and
every later message replying to or threading on that poll. Drop
malformed entries (and return null when nothing valid remains)
instead of throwing.
* fix(matrix): normalize malformed poll text
Signed-off-by: sallyom <somalley@redhat.com>
* fix(matrix): use guarded poll records
Signed-off-by: sallyom <somalley@redhat.com>
---------
Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
Centralize untrusted audio transcript framing across channel plugins and keep Discord voice transcripts out of typed command provenance.
Co-authored-by: xialonglee <li.xialong@xydigit.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(matrix): recognize room version 12 room IDs (no :server suffix)
Room version 12 (MSC4291) dropped the trailing ":server" from room
IDs -- they are now a hash of the create event. Every place in the
Matrix plugin that treated "!" + ":" as the signature of an
already-resolved room ID silently discarded valid v12 room IDs as
unresolved instead of using them directly:
- channels.matrix.rooms config resolution (config.ts) dropped the
entry entirely, so group rooms could never pass the groupPolicy
"allowlist" gate on a v12 homeserver -- messages were dropped with
no reply and no default-level log line, since the only trace is a
verbose-only debug log.
- The invite auto-join allowlist validator and the interactive
group-room setup resolver in onboarding.ts had the same check
duplicated, so a user typing a v12 room ID during setup would be
told it was invalid.
- session-route.ts's per-room DM recipientSessionExact check had the
same gap for room-kind sends.
Runtime auto-join (auto-join.ts) already only checked for the "!"
sigil, which is why joining a v12 room worked while responding in it
did not -- this made the bug hard to spot from the join path alone.
Fix: add a single canonical isMatrixRoomId predicate next to the
existing isMatrixQualifiedUserId in target-ids.ts (user IDs and
aliases still require ":server" per spec; only room IDs changed) and
reuse it at all four sites instead of repeating the stale check.
Confirmed live against a real Room v12 homeserver (Conduit): the
server's own /joined_rooms response returns bare "!<hash>" room IDs
with no colon.
* docs(matrix): document suffixless room version 12 room IDs
Room version 12 (MSC4291) dropped the ":server" suffix from room
IDs. Document that the suffixless "!room" form is accepted anywhere
the docs previously only showed "!room:server", matching the
target-ids.ts fix landed in this same PR.
* fix(matrix): update stale Room v12 guidance text
* docs(matrix): accept suffixless Room v12 IDs in the group-policy guide
docs/channels/matrix.md already documents that channels.matrix.groups
accepts the suffixless !room form on room version 12+, but the
group-policy guide (docs/channels/groups.md) still only listed
!room:server, contradicting the channel doc an operator on a v12
homeserver would actually be following.
Addresses the ClawSweeper P2 finding on PR #123931.
* fix(matrix): advertise suffixless Room v12 IDs in onboarding placeholders
The invite auto-join and group-room setup prompts' placeholder text
still showed only `!roomId:server`, even though the retry note,
validation, and unresolved-room diagnostic already accept and describe
the suffixless `!roomId` form on room version 12+. An operator on a
v12 homeserver would see their homeserver's own room IDs contradicted
by the very placeholder guiding them through setup.
Updated both placeholders to list the suffixless form alongside the
existing examples, matching the phrasing already used in
docs/channels/matrix.md and the invite retry note. Added
configureRoomsAccess/roomsAllowlist options to the shared
createMatrixUpdateKeepCredentialsPrompter test harness (mirroring the
existing inviteAutoJoin option) so the group-room setup flow can be
exercised without duplicating the base prompter setup, then added
focused tests asserting the exact placeholder text for both prompts.
Verified both new tests fail against the pre-fix placeholders and pass
after.
Addresses the two ClawSweeper P2 findings on PR #123931.
* test(matrix): restore only allowlisted environment keys
* fix(matrix): reject empty room identifiers
---------
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Reject unbound foreign-channel fallback at shared approval-account selection while preserving recorded bindings and explicit forwarding targets. Cover Telegram and Matrix routing contracts.
Co-authored-by: vatsalgargg <vatsalg80@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
On a pristine profile, onboarding/doctor printed "Auto-migrated legacy
state: Recorded Matrix inbound dedupe migration completion (0 SQLite
roots, 0 JSON roots scanned)" even though nothing was migrated. Keep
the durable empty-scan receipt (it still prevents later historical
databases from being opened) but only emit the user-visible change line
when at least one SQLite/JSON root was scanned.
* refactor: consolidate coercion ownership
Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.
The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.
* fix: guard integer option ownership
Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.
* fix: keep integer helpers on numeric facade
Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.
* fix: point numeric coercion to number runtime
Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
Unset heartbeat.target now resolves "owner": elected heartbeat notifications deliver to the operator's DM resolved from commands.ownerAllowFrom or the channel allowFrom (first concrete entry; wildcards and channel-scoped wildcards excluded; configured owners exhausted across channels before any channel-local fallback). Delivery requires the channel's own classifier to positively prove a direct destination — every bundled messaging plugin now ships an inferTargetChatType contract — and unproven or group-shaped destinations fail closed to the visible no-route state. The first implicitly-routed delivery carries a one-line self-explanation naming the target: "none" opt-out. Explicit target "last" remains as the follow-the-conversation opt-in. Refines the unreleased #121892 default before it ships; refs #121880.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>