fix: resolve 10 port bugs found by systematic scan#16
Conversation
HIGH:
1. Discord card fallback table: call table_element_to_ascii(headers, rows)
instead of table_to_ascii with a synthetic dict
2. Teams card_to_fallback_text: delegate to shared implementation for
proper emoji conversion and consistent child rendering
3. Megaphone emoji: correct gchat unicode from U+1F4E3 to U+1F4E2
4. Exclamation emoji: remove spurious "!" gchat alias causing false matches
5. Queue dequeue (redis + postgres): reconstruct Message objects from
serialized dicts with _type == "chat:Message"
6. WhatsApp callback data: use compact JSON separators matching Telegram
7. Discord/Teams render_postable: add dataclass-style message support
and fall back to super() instead of returning empty string
MEDIUM:
8. Slack/GChat heading bold: document as intentional improvement (no-op)
9. from_slack strip: strip at most one colon from each end to avoid
stripping interior colons in edge-case emoji names
10. WellKnownEmoji: add 10 missing entries (stop, 100, lightbulb, pin,
inbox, outbox, file, coffee, pizza, beer)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request enhances message rendering and state management across multiple platform adapters. Key updates include adding support for dataclass-style messages in Discord and Teams, improving heading formatting for Google Chat and Slack, and refactoring card fallback logic to use shared implementations. Additionally, it updates emoji mappings, fixes Slack emoji parsing, and ensures proper deserialization of message objects in Postgres and Redis state stores. Feedback focuses on ensuring that Discord and Teams format converters utilize platform-specific fallback logic and mention conversion for card-based and object-style messages to maintain formatting consistency.
| return self.from_ast(message["ast"]) | ||
| return "" | ||
| if "card" in message or message.get("type") == "card": | ||
| return super().render_postable(message) |
There was a problem hiding this comment.
Instead of delegating to the generic base implementation, use the Discord-specific card_to_fallback_text and ensure mentions are converted. The base implementation uses a generic fallback that lacks emoji conversion and Discord-specific mention formatting.
| return super().render_postable(message) | |
| from chat_sdk.adapters.discord.cards import card_to_fallback_text as discord_card_fallback | |
| return self._convert_mentions_to_discord(discord_card_fallback(message.get("card") or message)) |
| if hasattr(message, "ast"): | ||
| return self.from_ast(message.ast) | ||
| # Fall back to base implementation for remaining cases (e.g. card objects) | ||
| return super().render_postable(message) |
There was a problem hiding this comment.
For object-style messages containing a card, use the Discord-specific fallback logic to ensure that emojis and mentions are correctly processed for the platform.
| return super().render_postable(message) | |
| if hasattr(message, "card"): | |
| from chat_sdk.adapters.discord.cards import card_to_fallback_text as discord_card_fallback | |
| return self._convert_mentions_to_discord(discord_card_fallback(message.card)) | |
| return super().render_postable(message) |
| return self.from_ast(message["ast"]) | ||
| return "" | ||
| if "card" in message or message.get("type") == "card": | ||
| return super().render_postable(message) |
There was a problem hiding this comment.
Delegating to super().render_postable for cards bypasses the Teams-specific fallback logic (which handles emoji conversion) and fails to convert @mentions to the <at>name</at> format required by Teams.
| return super().render_postable(message) | |
| from chat_sdk.adapters.teams.cards import card_to_fallback_text as teams_card_fallback | |
| return self._convert_mentions_to_teams(teams_card_fallback(message.get("card") or message)) |
| if hasattr(message, "ast"): | ||
| return self.from_ast(message.ast) | ||
| # Fall back to base implementation for remaining cases (e.g. card objects) | ||
| return super().render_postable(message) |
There was a problem hiding this comment.
Apply Teams-specific card fallback and mention conversion for object-style messages to maintain consistency with other message types.
| return super().render_postable(message) | |
| if hasattr(message, "card"): | |
| from chat_sdk.adapters.teams.cards import card_to_fallback_text as teams_card_fallback | |
| return self._convert_mentions_to_teams(teams_card_fallback(message.card)) | |
| return super().render_postable(message) |
Summary
Fixes 10 bugs found by systematically comparing the Python port against the TypeScript SDK, spanning 12 files across 7 adapter packages plus core modules.
HIGH priority (7 fixes):
table_to_ascii()with a synthetic dict; now correctly callstable_element_to_ascii(headers, rows)card_to_fallback_text()with Teams-specific formatting📣U+1F4E3, now📢U+1F4E2 matching TS)"!"gchat alias that caused false positive matches on literal exclamation marks_type == "chat:Message"are now reconstructed viaMessage.from_json()instead of staying as raw dictsseparators=(',', ':')matching Telegram's encodingsuper()fallback for card objectsMEDIUM priority (3 fixes):
strip(":")(which strips all colons) to stripping at most one colon from each endstop,100,lightbulb,pin,inbox,outbox,file,coffee,pizza,beerTest plan
🤖 Generated with Claude Code