xDDoubleTea’s blog

當我們還是小孩的時候,我們以為世界更為單純。
沒有贏不了的比賽,努力就會得到回報,沒有什麼事是不可能的。
一無所知,無知且愚蠢的孩子,用純真無垢的目光觀察世界後所產生的想法,那樣的想法——有錯嗎?
真的有錯嗎……?
—— 《遊戲人生 0》

DragonBot Ticket Close Hang

Context DragonBot is a customer-support ticket bot for a purchasing-agent business on Discord, written with discord.py. A customer opens a ticket, which is a private channel visible only to the customer and staff. Every status change renames the channel to {type}-{id:04d}-{status}, so staff can see the status from the channel list. Closing a ticket sets the status to CLOSED, exports the conversation with DiscordChatExporter, posts the transcript to an archive channel, and DMs the customer a feedback form. What Happened After a staff member confirmed closing a ticket, the bot sometimes sat on 「正在生成頻道紀錄以及傳送回饋單給顧客…」 for up to 10 minutes before the after-close buttons appeared. The owner reported it too. ...

October 10, 2026 · 4 min · xDDoubleTea

LeetCodeBot: One Session, Many Commands

Context LeetCodeBot talks to its database through AsyncDatabaseManager, an async context manager that hands out SQLAlchemy sessions: async with self.async_database_manager as db: db.add(row) # leaving the block commits, or rolls back on error main.py creates one manager and shares it across every cog. The old version looked like this: async def __aenter__(self) -> AsyncSession: self.session = self._sessionmaker() return self.session async def __aexit__(self, exc_type, exc_val, exc_tb): try: assert self.session if exc_type: await self.session.rollback() else: await self.session.commit() await self.session.close() except AssertionError: return True finally: return False It has two bugs (#38). Bug 1: __aexit__ commits the wrong session __aenter__ returns a new session, so the caller’s db is bound to that object. But __aexit__ reads self.session, which belongs to the shared manager. ...

August 28, 2026 · 5 min · xDDoubleTea

LeetCodeBot: The Bug the Async Migration Did Not Write

Context LeetCodeBot is a Discord bot for looking up and discussing LeetCode problems. It stores problems and their topic tags with SQLAlchemy on SQLite. In August 2026, #35 moved the database layer from synchronous SQLAlchemy to async (sqlite+aiosqlite). The bot kept running in production afterwards, with no errors. What happened A fresh clone could not start the bot. Deleting the database file to “start clean” made it fail every time: sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place? File "core/leetcode_problem.py", line 420, in add_problem_to_db if db_tag not in db_problem.tags: The failing expression is a plain attribute read: db_problem.tags. ...

August 28, 2026 · 4 min · xDDoubleTea

Kcalc Self Deadlock

Context kcalc is a calculator running directly in kernelspace. Achieved by loading as a Linux kernel module, and by exposing a character device /dev/kcalc_chardev to the userspace, supporting read, write operations. A process write the expression they want to evaluate to /dev/kcalc_chardev. That process then read from /dev/kcalc_chardev. The character device is locked whenever a process is writing to/reading from it via mutex_lock();. The kernel is tested using pytest, calls tee and cat for write and read operations respectively What Happened When running the pytest suite, the process hangs indefinitely, no cases is passed or failed. It is also unkillable. Opening btop reveals that the cat process is there hanging, and causing the pytest which calls cat as a subprocess hangs. The cat process is unkillable even with SIGKILL. ...

August 22, 2026 · 3 min · xDDoubleTea

Hello World

This is the first post on my new Hugo blog. Hello, world!

August 18, 2026 · 1 min · xDDoubleTea