Problem
A user added to an open cowork group can talk immediately but is never written to that group's allowed_users. The roster stays empty, so there is no record of who actually used the bot there.
Mechanism, confirmed
user_allowed short-circuits on the open flag (config/types.rs:464):
.is_some_and(|g| g.open || Self::id_in(&g.allowed_users, uid))
g.open is true, so the allow-list is never consulted.
Lazy registration then never fires, because it is gated on the ACL having FAILED (handler.rs:781):
if !acl_passed && !is_dm && is_cowork_group(...) {
auto_register_to_group(...)
}
In an open group acl_passed is already true, so the branch is skipped. Registration survives only on three narrow paths: a non-bot new_chat_members event, /start, or an ACL rejection — and open groups defeat the third.
The code's own comment says the roster is meant to exist (handler.rs:644):
open=true already allows every member; the allowlist entry just keeps a visible roster of who's in.
It just has no path that populates it in the case it describes.
Why it matters
- No audit trail. There is no record of who used the bot in that group.
open is not reversible. Turning it off locks out every existing member, because none were ever written to the list. What looks like tightening a setting is a silent mass revocation.
Fix
Register on first message regardless of whether the ACL already passed: record the user if absent, then continue. Membership becomes a consequence of participating rather than of being rejected first.
Care
- Must not widen access. Registration is a record of someone already permitted; it must never be what grants permission. A user the ACL rejects in a NON-open group must still be rejected.
- Bots stay excluded, matching the existing join path.
- Idempotent and quiet. It runs on every message, so an already-registered user must be a cheap no-op with no repeated config writes and no log spam.
Not included
The stuck "Add to Group" sheet reported alongside this is a separate surface. The button is a URL button opening Telegram's native ?startgroup= picker, so there is no callback to answer and no API to dismiss it — the bot cannot close that sheet. Whether the inline &admin= rights request (#709) makes the picker wait on an extra confirmation is untested, and testing it needs a client, not a code change.
Problem
A user added to an open cowork group can talk immediately but is never written to that group's
allowed_users. The roster stays empty, so there is no record of who actually used the bot there.Mechanism, confirmed
user_allowedshort-circuits on the open flag (config/types.rs:464):g.openis true, so the allow-list is never consulted.Lazy registration then never fires, because it is gated on the ACL having FAILED (
handler.rs:781):In an open group
acl_passedis already true, so the branch is skipped. Registration survives only on three narrow paths: a non-botnew_chat_membersevent,/start, or an ACL rejection — and open groups defeat the third.The code's own comment says the roster is meant to exist (
handler.rs:644):It just has no path that populates it in the case it describes.
Why it matters
openis not reversible. Turning it off locks out every existing member, because none were ever written to the list. What looks like tightening a setting is a silent mass revocation.Fix
Register on first message regardless of whether the ACL already passed: record the user if absent, then continue. Membership becomes a consequence of participating rather than of being rejected first.
Care
Not included
The stuck "Add to Group" sheet reported alongside this is a separate surface. The button is a URL button opening Telegram's native
?startgroup=picker, so there is no callback to answer and no API to dismiss it — the bot cannot close that sheet. Whether the inline&admin=rights request (#709) makes the picker wait on an extra confirmation is untested, and testing it needs a client, not a code change.