7 documents covering stack, integrations, architecture, structure, conventions, testing, and concerns.
16 KiB
16 KiB
Codebase Concerns
Analysis Date: 2026-04-01
Tech Debt
Telegram adapter not merged to main
- Issue: The entire
adapter/telegram/directory exists only in thefeat/telegram-adapterbranch (worktree at.worktrees/telegram/).mainhas no Telegram adapter at all. - Files:
.worktrees/telegram/adapter/telegram/and remote branchorigin/feat/telegram-adapter - Impact: Running
python -m adapter.telegram.botfrommainfails with ImportError. Tests referencingadapter/telegram/(e.g.,tests/adapter/test_forum_db.py) only exist in the worktree and are absent frommain. - Fix approach: Merge
feat/telegram-adapterintomainafter final manual QA pass. The branch is ahead of main by 5 commits (a1b7a14being the most recent).
Divergent core/handlers between main and feat/telegram-adapter
- Issue:
feat/telegram-adapterremoved platform-awareness fromcore/handlers/chat.pyandcore/handlers/message.py— the_command()and_start_command()helpers that format Matrix!cmdvs Telegram/cmdprompts were deleted. The branch hardcodes/starteverywhere. - Files:
core/handlers/chat.py,core/handlers/message.py(differ between branches) - Impact: If the Matrix adapter relies on these platform-aware helpers being in
main's version of core, mergingfeat/telegram-adapterwill break Matrix!startprompt text for unauthenticated users. - Fix approach: Before merging, decide which version of
core/handlers/is canonical. The Matrix adapter inmaincurrently passes becausemainstill has the platform-aware helpers.
SQLiteStore uses blocking I/O in async context
- Issue:
core/store.pySQLiteStoremethods are declaredasyncbut perform synchronous blockingsqlite3.connect()calls withoutasyncio.to_threadoraiosqlite. - Files:
core/store.pylines 46–73 - Impact: Each database call blocks the asyncio event loop. Under any concurrent load (e.g., two Matrix users sending messages simultaneously) this will cause visible latency spikes and potential event loop starvation.
- Fix approach: Replace
sqlite3calls withaiosqliteor wrap each call inasyncio.to_thread().
Telegram adapter has its own separate SQLite database layer
- Issue:
adapter/telegram/db.pyis a fully independent SQLite database (file:lambda_bot.db) with its own schema (tg_users,chats). Meanwhile,core/store.pyhasSQLiteStorewith a KV schema (lambda_matrix.dbfor Matrix). The two stores are incompatible and do not share data. - Files:
.worktrees/telegram/adapter/telegram/db.py,core/store.py - Impact: There is no unified storage layer. Chat state is split across two databases. A user's Telegram chats cannot be seen from Matrix and vice versa (even conceptually). Violates the "single core" architecture principle from CLAUDE.md.
- Fix approach: This is a fundamental design gap. Either extend
StateStoreto support the Telegram-specific data model, or accept separate stores as intentional for the prototype stage and document the constraint.
MockPlatformClient hardcoded throughout — no production path wired
- Issue: Both
adapter/matrix/bot.pyand.worktrees/telegram/adapter/telegram/bot.pyinstantiateMockPlatformClient()directly.PLATFORM_MODEis defined in.env.examplebut is never read or acted upon anywhere in the codebase. - Files:
adapter/matrix/bot.pyline 71,sdk/mock.py,sdk/interface.py - Impact: There is no runtime switch to connect a real SDK. Switching to production requires code changes, not configuration.
- Fix approach: Add a factory function in
sdk/that readsPLATFORM_MODEand returns eitherMockPlatformClientor a realPlatformClient. Both bot entrypoints should use this factory.
MatrixRuntime type annotation leaks MockPlatformClient
- Issue:
adapter/matrix/bot.pyMatrixRuntime.platformis typed asMockPlatformClient(notPlatformClient).build_event_dispatcherandbuild_runtimesignatures also useMockPlatformClientas the parameter type. - Files:
adapter/matrix/bot.pylines 46, 54, 67 - Impact: The isolation promise ("replace only
sdk/mock.pywhen real SDK arrives") is broken — the bot layer is coupled to the mock concrete type, not the Protocol. - Fix approach: Change type annotations to
PlatformClientfromsdk.interface.
Known Bugs / Open Issues
Telegram forum: global commands visible inside topic context
- Issue: Telegram shows the full bot command menu (including
/chats,/new,/settings) even when the user is inside a forum topic. The code blocksswitchandnew_chatcallbacks inside topics but the commands themselves still appear in the UI. - Files:
.worktrees/telegram/adapter/telegram/handlers/forum.py,.worktrees/telegram/adapter/telegram/bot.py - Impact: Users can tap
/settingsor/chatsinside a topic and get confusing behavior. - Tracked: Issue
#15—Telegram forum topics: remaining UX and synchronization gaps
Telegram forum: /new <name> inside linked topic does not rename the Telegram topic
- Issue: Running
/new <name>inside a forum topic that is already linked to a chat renames the internal chat record but does not calledit_forum_topicto rename the actual Telegram topic. - Files:
.worktrees/telegram/adapter/telegram/handlers/forum.py - Impact: Topic name in Telegram goes out of sync with internal chat name.
- Tracked: Issue
#15
Matrix: handle_invite hardcodes chat_id = "C1" for all new rooms
- Issue:
adapter/matrix/handlers/auth.pyhandle_invite()always assignschat_id = "C1"regardless of how many rooms the user already has. If a user invites the bot into a second room before using!new, both rooms getC1. - Files:
adapter/matrix/handlers/auth.pyline 26 - Impact: Two rooms mapped to the same
chat_idcauses routing collisions. - Fix approach: Call
next_chat_id(store, user_id)here instead of hardcoding"C1".
Matrix: remove_reaction uses non-standard undo field
- Issue:
adapter/matrix/reactions.pyremove_reaction()sends a"undo": Truefield in the reaction event body. This is not part of the Matrix spec for reaction redaction. The correct approach is to redact the original reaction event viaclient.room_redact(). - Files:
adapter/matrix/reactions.pylines 56–68 - Impact: Reaction "undo" will silently fail on compliant homeservers.
Matrix: E2EE not supported (blocked by python-olm)
- Issue:
matrix-nioE2EE requirespython-olm, which fails to build on macOS/ARM. No encrypted DM support. - Files:
adapter/matrix/bot.py - Impact: The bot cannot operate in encrypted rooms. Users who have DM encryption enforced cannot use the Matrix bot.
- Status: Documented as a known infrastructure constraint in
docs/reports/2026-04-01-surfaces-progress-report.md. Needs a separate infrastructure task.
Security Considerations
SQLite database files not in .gitignore
- Risk:
lambda_bot.dbandlambda_matrix.dbare present in the working tree (shown ingit status) but not listed in.gitignore. These files may contain user data including chat content and display names. - Files:
lambda_bot.db,lambda_matrix.db,.gitignore - Current mitigation: Files are currently untracked (not yet staged) but nothing prevents them from being accidentally committed.
- Recommendation: Add
*.dbor specific filenames to.gitignoreimmediately.
Auth flow is auto-confirmed in mock — no real validation exists
- Issue:
core/auth.pyconfirm()automatically setsstate = "confirmed"and generates a fakeplatform_user_id. There is no real verification step, no code exchange, no token validation. - Files:
core/auth.pylines 39–48 - Impact: The auth layer is decorative for the prototype. Any user who sends
!startor/startis immediately authenticated. If the real SDK auth requires a different flow (e.g., OAuth, code), the currentAuthManagerinterface may not match. - Current mitigation: Acceptable for mock stage. Must be re-evaluated before production use.
Matrix room metadata stored without access control
- Issue:
adapter/matrix/store.pystores room metadata keyed byroom_id. Any call that can supply an arbitraryroom_idcan read or overwrite another user's room metadata. - Files:
adapter/matrix/store.py,adapter/matrix/room_router.py - Impact: In the current single-process bot this is not exploitable. If the store is ever shared across processes or users, room metadata can be poisoned.
Fragile Areas
core/chat.py scan-by-suffix fallback is O(N) and collision-prone
- Issue:
ChatManager.get()when called withoutuser_idscans allchat:*keys and matches by suffix (e.g.,":C1"). If two users both have a chat namedC1(which is always the case), this returns the first one found, non-deterministically. - Files:
core/chat.pylines 76–82 - Impact: Functions like
renameandarchivethat callchat_mgr.get(chat_id)withoutuser_idwill operate on the wrong user's chat in a multi-user scenario. - Fix approach: Audit all callers and always pass
user_id. The scan-by-suffix fallback should be removed or explicitly guarded.
adapter/matrix/handlers/chat.py chat_id counter races under concurrency
- Issue:
make_handle_new_chatcallschat_mgr.list_active()and useslen(chats) + 1to compute a newchat_id. This is not atomic. Two concurrent!newcommands from the same user can produce the samechat_id. - Files:
adapter/matrix/handlers/chat.pyline 17 - Impact: Duplicate
chat_idvalues (C2,C2) for the same user, leading to state corruption. - Fix approach: Use
next_chat_id()fromadapter/matrix/store.pywhich increments an atomic counter in the store. Thenext_chat_id()function already exists but is not used here.
conftest.py contains a fragile stdlib platform module workaround
- Issue:
conftest.pypatchessys.modulesto remove the Python stdlibplatformmodule so localplatform/(which no longer exists — renamed tosdk/) doesn't shadow it. The comment still refers toplatform/but the directory was renamed tosdk/in commit41660fe. - Files:
conftest.pylines 1–13 - Impact: The workaround is now a no-op (there is no
platform/package to shadow) but adds confusion. The comment is incorrect. If someone creates aplatform/directory again, unexpected behavior can return. - Fix approach: Remove the
sys.modulespatching entirely sincesdk/does not conflict with stdlib. Update the comment.
Forum onboarding chat_shared constructs a fake Chat object
- Issue:
adapter/telegram/handlers/forum.pyhandleschat_sharedby constructingChat(id=..., type="supergroup", is_forum=True)and passing it to_complete_group_link(). Theis_forum=Trueis hardcoded — the real value from Telegram is not verified. This means the checkif getattr(forwarded_chat, "is_forum", None) is Falsein the forwarding fallback path is bypassed entirely. - Files:
.worktrees/telegram/adapter/telegram/handlers/forum.pylines 162–168 - Impact: A user could link a regular supergroup (without Topics enabled) via
chat_shared, which would succeed in linking but fail when the bot tries to create forum topics.
Gaps Between CLAUDE.md and Actual Code
CLAUDE.md says platform/ — code uses sdk/
- CLAUDE.md architecture diagram shows
platform/interface.pyandplatform/mock.py - Actual code uses
sdk/interface.pyandsdk/mock.py(renamed in commit41660fe) - Files:
CLAUDE.md(project instructions),sdk/interface.py,sdk/mock.py - Also: Agent config files at
.claude/agents/core-developer.mdstill referenceplatform/throughout - Impact: New contributors reading CLAUDE.md will look for a
platform/directory that does not exist.
CLAUDE.md lists core/handlers/ sub-handlers that partially do not exist
- CLAUDE.md lists handler modules but the actual
core/handlers/only has:start.py,message.py,chat.py,settings.py,callback.py - No
voice.pyhandler exists; voice is handled as a fallback insidecore/handlers/message.py(returns stub response) - No
payment.pyhandler exists;PaymentRequireddataclass is defined incore/protocol.pybut never dispatched - Files:
core/protocol.py(PaymentRequired defined),core/handlers/(no payment or voice handlers)
CLAUDE.md workflow describes @reviewer agent but agent file references old patterns
.claude/agents/core-developer.mdstill says "Твоя зона —core/иplatform/"- The old Haiku/Sonnet researcher-developer workflow is captured in
docs/workflow-backup-2026-04-01.md, but.claude/agents/configs were not updated to match
tests/adapter/test_forum_db.py is untracked on main
- This test file exists in the working tree (visible in
git status) but is not committed tomain. It testsadapter/telegram/db.pywhich also does not exist onmain. - Files:
tests/adapter/test_forum_db.py - Impact: Running
pytest tests/from main currently includes this test, which importsadapter.telegram.db. This import succeeds only because the test auto-reloads the module from an untracked file. This is fragile — if the file is deleted, tests silently pass with fewer tests counted.
Missing Critical Features
No streaming response support in adapters
- Both adapters use
platform.send_message()(sync) notplatform.stream_message()(streaming) sdk/interface.pydefinesstream_messagereturningAsyncIterator[MessageChunk]- No adapter sends a typing indicator before the response arrives and then streams chunks
- Impact: User experience with slow AI responses will show nothing until the full response is ready
- Files:
core/handlers/message.pyline 28,sdk/interface.pylines 83–88
No webhook/push notification handling
sdk/interface.pydefinesWebhookReceiverProtocol withon_agent_event()sdk/mock.pyhasregister_webhook_receiver()andsimulate_agent_event()- Neither bot entrypoint registers a
WebhookReceiver - Impact: Push notifications from the platform (task completions, background jobs) cannot reach the user
- Files:
sdk/interface.pylines 95–97,adapter/matrix/bot.py, no registration present
Telegram adapter uses InMemoryStore for core state
.worktrees/telegram/adapter/telegram/bot.pycallsInMemoryStore()for theEventDispatcher's state- All
core/state (auth, chat metadata in the KV layer) is lost on bot restart adapter/telegram/db.pySQLite is used only for Telegram-specific data- Impact: On restart, authenticated users are logged out; core chat context is wiped
- Files:
.worktrees/telegram/adapter/telegram/bot.pyline 46
No multi-user isolation in Matrix store
adapter/matrix/store.pykeys are global (matrix_room:ROOMID,matrix_user:USERID)- There is no namespace or tenant isolation
- Impact: At scale, any key collision would corrupt state. For a single-user prototype this is acceptable, but it is an architectural constraint to document before expanding scope.
Test Coverage Gaps
No tests for adapter/telegram/ in main test suite
tests/adapter/on main only containsmatrix/tests and the untrackedtest_forum_db.py- All Telegram adapter tests live in the worktree at
.worktrees/telegram/tests/ - Files:
tests/adapter/(missingtelegram/subdirectory on main) - Risk: Merging
feat/telegram-adapterwithout also merging its tests leaves Telegram untested on main - Priority: High
No tests for core/handlers/callback.py confirm/cancel real behavior
core/handlers/callback.pyhandle_confirmandhandle_cancelreturn stub text withaction_id- No test verifies that a real confirmation flow (dispatch → confirm → side effect) works end to end
- Files:
core/handlers/callback.py,tests/core/test_dispatcher.py - Priority: Medium
No tests for adapter/matrix/handlers/auth.py multi-room invite scenario
- The hardcoded
C1bug (see Known Bugs section) is not caught by any test - Files:
adapter/matrix/handlers/auth.py,tests/adapter/matrix/test_dispatcher.py - Priority: Medium
Concerns audit: 2026-04-01