Skip to content

fix: resolve 10 port bugs found by systematic scan#16

Merged
patrick-chinchill merged 1 commit into
mainfrom
fix/systematic-scan-port-bugs
Apr 7, 2026
Merged

fix: resolve 10 port bugs found by systematic scan#16
patrick-chinchill merged 1 commit into
mainfrom
fix/systematic-scan-port-bugs

Conversation

@patrick-chinchill
Copy link
Copy Markdown
Collaborator

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):

  • Discord card fallback table: was calling table_to_ascii() with a synthetic dict; now correctly calls table_element_to_ascii(headers, rows)
  • Teams card_to_fallback_text: hand-rolled implementation skipped emoji conversion; now delegates to the shared card_to_fallback_text() with Teams-specific formatting
  • Megaphone emoji: wrong unicode glyph (was 📣 U+1F4E3, now 📢 U+1F4E2 matching TS)
  • Exclamation emoji: removed spurious "!" gchat alias that caused false positive matches on literal exclamation marks
  • Queue dequeue (Redis + Postgres): deserialized messages with _type == "chat:Message" are now reconstructed via Message.from_json() instead of staying as raw dicts
  • WhatsApp callback data: added compact JSON separators=(',', ':') matching Telegram's encoding
  • Discord/Teams render_postable: added missing dataclass-style message object support and proper super() fallback for card objects

MEDIUM priority (3 fixes):

  • Slack/GChat heading bold wrapper: documented as intentional improvement (Slack mrkdwn and GChat have no heading syntax, so bold wrapping is a reasonable adaptation)
  • from_slack colon stripping: changed from strip(":") (which strips all colons) to stripping at most one colon from each end
  • WellKnownEmoji Literal: added 10 missing entries that exist in the emoji map but were absent from the type: stop, 100, lightbulb, pin, inbox, outbox, file, coffee, pizza, beer

Test plan

  • All 2483 existing tests pass
  • Updated WhatsApp callback data tests to assert compact JSON format
  • ruff check + format clean on all modified files
  • Verify Discord table fallback renders correctly in embed fallback text
  • Verify Teams fallback text includes emoji conversion
  • Verify queue round-trip: enqueue Message -> dequeue returns Message (not dict)

🤖 Generated with Claude Code

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>
@patrick-chinchill patrick-chinchill merged commit 1a1f8b5 into main Apr 7, 2026
5 checks passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Apply Teams-specific card fallback and mention conversion for object-style messages to maintain consistency with other message types.

Suggested change
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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant