docs: evaluate tsdeclarations codegen, map permissions, verify encoding (TODO-063,068,069)

tsdeclarations eval: direct codegen redundant (already via tsproto),
but permission ID generation and error code enum have high value.
Permission mapping: 253 TS3 permissions identified, 7 P1 for chat/moderation.
Encoding verification: tsclientlib uses strict UTF-8, UCS-2 is edge case.
This commit is contained in:
Edison Jwa
2026-06-11 20:54:40 +09:00
parent 508fa8b408
commit 7968f90f7d
4 changed files with 682 additions and 1 deletions
@@ -457,6 +457,7 @@
- **Description:** Chanora forks `tsclientlib` for a p256 fix. Submit PR upstream to reduce fork maintenance burden.
- **Effort:** M
- **Dependencies:** None
- **Status:** PR DRAFT READY — `docs/references/upstream-p256-pr-draft.md` (2026-06-11)
### TODO-058 — Monitor tsdeclarations for TS5 protocol updates
- **Priority:** P2
@@ -464,6 +465,7 @@
- **Description:** No full TS5 client protocol exists yet. Watch `tsdeclarations` repo for updates that may affect Chanora compatibility.
- **Effort:** S
- **Dependencies:** None (ongoing)
- **Status:** MONITORING — no TS5 protocol updates detected; `tsdeclarations` last checked 2026-06-11
### TODO-059 — Build auto-reconnect logic internally
- **Priority:** P2
@@ -488,6 +490,7 @@
- **Description:** YaTQA's `/ressourcen/` section has comprehensive unofficial server error codes. Extract for Chanora error handling reference.
- **Effort:** S
- **Dependencies:** None
- **Status:** VERIFIED COMPLETE — 170+ error codes in yatqa-offline-reference.md §9, cross-reference with ReSpeak in §13 (2026-06-11)
### TODO-061 — Extract anti-flood/rate-limiting reference from YaTQA
- **Priority:** P3
@@ -495,6 +498,7 @@
- **Description:** YaTQA documents anti-flood mechanics and rate limiting. Use as reference when implementing Chanora's rate limiting.
- **Effort:** S
- **Dependencies:** None
- **Status:** PARTIALLY COMPLETE — summary tiers in yatqa-offline-reference.md §5; detailed action table still needs backfill (see TODO-081)
---
@@ -521,7 +525,8 @@
- **Description:** TS claims UTF-8 but uses UCS-2 (BMP only). Mobile apps use CESU-8. Server 3.2.0+ adds partial emoji support. tsclientlib/tsproto delivers Rust `String` (UTF-8) via `str::from_utf8()` at the protocol layer (ReSpeak §1.8.3 confirms: "Command string encoded in UTF-8"). If encoding bugs exist, the fix belongs in the EdisonJwa/tsclientlib fork, not in chanora_protocol.
- **Verification:** Confirm tsclientlib handles UCS-2 correctly. Document encoding behavior in protocol-implementation-traps.md (TODO-070).
- **Effort:** S (verification + documentation)
- **Status:** Scope revised from implementation to verification (2026-06-11)
- **Status:** VERIFIED — strict UTF-8 via `str::from_utf8()`, no UCS-2/CESU-8 code exists, non-UTF-8 causes errors not corruption (2026-06-11)
- **Evidence:** `docs/references/encoding-verification.md`
- **Dependencies:** TODO-070 (protocol traps doc)
### TODO-064 — Implement client-side anti-flood point awareness
@@ -579,6 +584,7 @@
- **Description:** TS3 server 3.1.6-3.1.7 has IPv6 canonicalization bug in Blacklist2 protocol. Chanora should be aware when connecting to older servers.
- **Effort:** S
- **Dependencies:** None
- **Status:** DOCUMENTED — trap #6 in protocol-implementation-traps.md (2026-06-11)
### TODO-072 — Establish connection/message performance benchmarks
- **Priority:** P3
@@ -586,6 +592,7 @@
- **Description:** tsclientlib benchmarks: ~199ms connect, ~189µs/message. Use as baseline for Chanora's performance testing.
- **Effort:** S
- **Dependencies:** None
- **Status:** DOCUMENT CREATED — `docs/references/performance-benchmarks.md` (2026-06-11)
### TODO-073 — Assess web client feasibility
- **Priority:** P3
@@ -593,6 +600,7 @@
- **Description:** TeaSpeak's web client was a compelling installation-less option. Evaluate whether a future Chanora web client makes sense. Not current scope.
- **Effort:** S
- **Dependencies:** None
- **Status:** ASSESSMENT COMPLETE — `docs/references/web-client-feasibility.md`; verdict: defer indefinitely (UDP transport blocker) (2026-06-11)
---
+102
View File
@@ -0,0 +1,102 @@
# tsclientlib Encoding Handling Verification
**Date:** 2026-06-11
**Scope:** Verification of encoding handling in Chanora's tsclientlib fork
**Checkout analyzed:** `~/.cargo/git/checkouts/tsclientlib-b9d0d0212095a0c5/3fbfa26/`
---
## 1. How tsclientlib Handles Encoding
### Command Layer (`tsproto-packets/src/commands.rs`)
The `CommandParser` operates on raw `&[u8]` bytes. String conversion happens at the value level:
- **`CommandArgumentValue::get_str()`** (line 157): Returns `Result<Cow<'a, str>>` using `str::from_utf8()` on raw bytes or `String::from_utf8()` on unescaped bytes.
- **`CommandArgumentValue::get_parse()`** (line 166): Calls `get_str()` then `.parse()` for typed values.
- Both methods return `Utf8Error` on invalid UTF-8 — **strict validation, not lossy**.
### Packet Layer (`tsproto/src/`)
| File | Line | Usage | Behavior |
|------|------|-------|----------|
| `license.rs` | 482, 550 | `str::from_utf8(&data[...])` | Strict — returns `Error::DeserializeString` on failure |
| `log.rs` | 84, 101 | `if let Ok(s) = str::from_utf8(packet.content())` | Silent skip — invalid UTF-8 packets are not logged |
| `client.rs` | 363 | `str::from_utf8(name)` | Used in error message formatting only |
| `algorithms.rs` | 450 | `String::from_utf8_lossy(&dec)` | Lossy — only in debug `println!` |
### Bookkeeping Layer (`utils/ts-bookkeeping/`)
- All string fields in `Connection`, `Server`, `Client`, `Channel` structs are `String` (Rust's UTF-8 type).
- Generated message parsers (via `MessageDeclarations.tt` line 47) use `str::from_utf8(s)?.to_string()` — strict UTF-8 validation.
- `ParseError::StringParse` wraps `std::str::Utf8Error` (messages.rs:26).
---
## 2. UCS-2 and CESU-8 Handling
**No UCS-2 or CESU-8 code exists anywhere in the fork.**
Search for `ucs`, `UCS`, `cesu`, `CESU`, `utf16`, `UTF16`, `utf-16`, `UTF-16` across all `.rs` files returned zero results.
The fork treats all protocol data as UTF-8 bytes. There is no:
- UCS-2 to UTF-8 conversion
- CESU-8 decoding
- UTF-16 handling
- Encoding detection or negotiation
---
## 3. What Happens with Non-UTF-8 Data
If the server sends non-UTF-8 bytes (e.g., UCS-2 encoded emoji from an older client):
| Layer | Behavior |
|-------|----------|
| `CommandParser::get_str()` | Returns `Err(Utf8Error)` — call site decides |
| License parsing | Returns `Err(Error::DeserializeString)` — connection fails |
| Log parsing | `if let Ok(s)` — silently skipped, packet not logged |
| Message parsing | Returns `Err(ParseError::StringParse)` — command rejected |
**Critical:** There is no graceful fallback. Non-UTF-8 data causes errors at the protocol layer.
---
## 4. What the TS3 Protocol Actually Sends
Per ReSpeak protocol reference §1.8.3: "Command string encoded in UTF-8"
The TS3 protocol itself uses UTF-8 for command strings. The UCS-2 concern applies to:
- **Older mobile clients** (pre-3.2.0) that may send CESU-8 encoded supplementary characters
- **Server-side storage** where some servers may store UCS-2 for certain fields
- **Emoji support** added in Server 3.2.0+ (UTF-8 with full Unicode)
In practice, the protocol wire format is UTF-8. The UCS-2 issue is a server/client implementation detail, not a protocol encoding issue.
---
## 5. Risks for Chanora
### Low Risk
- **Normal operation:** Modern TS3 servers and clients send valid UTF-8. No issues expected.
- **Chanora's own strings:** Always valid UTF-8 (Rust `String` type guarantees this).
### Medium Risk
- **Legacy clients:** Older mobile clients sending CESU-8 will cause `Utf8Error` in command parsing. Commands will be rejected, not silently corrupted.
- **Server names/channel names with emoji:** If a server stores names in UCS-2 format (some older databases), Chanora will fail to parse them.
### Mitigation
- The fork uses **strict** UTF-8 validation (not lossy). This is correct behavior — rejecting malformed data is safer than silently corrupting it.
- If UCS-2 compatibility is needed, the fix belongs in the `EdisonJwa/tsclientlib` fork, not in Chanora's protocol layer.
---
## 6. Conclusion
tsclientlib handles encoding correctly for the TS3 protocol:
- All string parsing uses `str::from_utf8()` — strict UTF-8 validation
- No UCS-2/CESU-8 code exists — the fork assumes UTF-8 wire format
- Invalid UTF-8 causes errors, not silent corruption
- The protocol itself is UTF-8; UCS-2 is an edge case from legacy implementations
**Status:** VERIFIED — encoding handling is correct as-is.
+428
View File
@@ -0,0 +1,428 @@
# TS3 Permission ID Mapping to Chanora
**TODO-069** — Map TS3 permissions to Chanora's permission system.
---
## 1. TS3 Permission System Overview
### 1.1 Permission Tiers (from YaTQA §1.2)
Permissions are evaluated top-to-bottom, lowest tier wins:
| Tier | Level | Description |
|------|-------|-------------|
| 0 | Server Groups | Highest value wins (unless Negate flag) |
| 1 | Client (Server level) | Client-specific server permissions |
| 2 | Channel | Skipped if Skip flag set |
| 3 | Channel Group | Skipped if Skip flag set |
| 4 | Client (Channel level) | Client-specific channel permissions |
### 1.2 Permission Types (from Enums.toml)
| Type | ID1 | ID2 |
|------|-----|-----|
| ServerGroup | ServerGroupId | 0 |
| GlobalClient | ClientDbId | 0 |
| Channel | ChannelId | 0 |
| ChannelGroup | ChannelId | ChannelGroupId |
| ChannelClient | ChannelId | ClientDbId |
### 1.3 Special Flags
- **Skip flag**: Skips channel and channel group permissions
- **Negate flag**: If ANY server group has Negate, only Negate groups count
- **Grant permission**: `i_needed_permission_modify_power_*` — controls who can modify a permission
---
## 2. Chanora's Current Permission Handling
### 2.1 What Exists
| Component | Permission Handling | Location |
|-----------|-------------------|----------|
| `chanora_bridge::permission_jni` | Android `RECORD_AUDIO` runtime permission only | `crates/chanora_bridge/src/permission_jni.rs` |
| `chanora_bridge::api::PermissionStateKind` | Android permission state enum (Granted/Denied/PermanentlyDenied) | `crates/chanora_bridge/src/api.rs` |
| `chanora_core` | No TS3 permission model | — |
| `chanora_protocol` | Error code `0x0a08` (permissions_client_insufficient) recognized but no permission ID mapping | `crates/chanora_protocol/src/lib.rs:109` |
| `chanora_protocol::adapter` | Permission-gated fields (e.g., `client_address` empty when no permission) | `crates/chanora_protocol/src/dto.rs:181` |
| `VoiceJoinErrorCode::JoinDenied` | Generic "denied by server policy/permission" | `core/chanora_core/src/events.rs:267` |
### 2.2 What Does NOT Exist
- No TS3 permission ID constants
- No permission evaluation engine (Skip/Negate/Grant logic)
- No per-permission checks before protocol commands
- No permission-aware UI gating
- No server group / channel group permission tracking
---
## 3. Permission ID Mapping
The following table maps all TS3 permission IDs from `Permissions.csv` / ReSpeak reference §3 to Chanora's current handling.
### 3.1 Server Instance Permissions
| Permission Name | Category | Chanora Status | Notes |
|----------------|----------|----------------|-------|
| `b_serverinstance_help_view` | Query | Not needed | ServerQuery only |
| `b_serverinstance_version_view` | Query | Not needed | ServerQuery only |
| `b_serverinstance_info_view` | Query | Not needed | ServerQuery only |
| `b_serverinstance_virtualserver_list` | Query | Not needed | ServerQuery only |
| `b_serverinstance_binding_list` | Query | Not needed | ServerQuery only |
| `b_serverinstance_permission_list` | Query | Not needed | ServerQuery only |
| `b_serverinstance_permission_find` | Query | Not needed | ServerQuery only |
| `b_virtualserver_create` | Admin | Not needed | Admin operation |
| `b_virtualserver_delete` | Admin | Not needed | Admin operation |
| `b_virtualserver_start_any` | Admin | Not needed | Admin operation |
| `b_virtualserver_stop_any` | Admin | Not needed | Admin operation |
| `b_virtualserver_change_machine_id` | Admin | Not needed | Admin operation |
| `b_virtualserver_change_template` | Admin | Not needed | Admin operation |
| `b_serverquery_login` | Query | Not needed | ServerQuery only |
| `b_serverinstance_textmessage_send` | Query | Not needed | ServerQuery only |
| `b_serverinstance_log_view` | Query | Not needed | ServerQuery only |
| `b_serverinstance_log_add` | Query | Not needed | ServerQuery only |
| `b_serverinstance_stop` | Admin | Not needed | Admin operation |
| `b_serverinstance_modify_settings` | Admin | Not needed | Admin operation |
| `b_serverinstance_modify_querygroup` | Admin | Not needed | Admin operation |
| `b_serverinstance_modify_templates` | Admin | Not needed | Admin operation |
### 3.2 Virtual Server Permissions
| Permission Name | Category | Chanora Status | Priority | Notes |
|----------------|----------|----------------|----------|-------|
| `b_virtualserver_select` | Query | Not needed | — | ServerQuery only |
| `b_virtualserver_info_view` | Read | **Implicit** | P3 | Used by `serverinfo` command |
| `b_virtualserver_connectioninfo_view` | Read | **Implicit** | P3 | Used by `serverrequestconnectioninfo` |
| `b_virtualserver_channel_list` | Read | **Implicit** | P3 | Used by `channellist` command |
| `b_virtualserver_channel_search` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_client_list` | Read | **Implicit** | P3 | Used by `clientlist` command |
| `b_virtualserver_client_search` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_client_dblist` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_client_dbsearch` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_client_dbinfo` | Read | **Implicit** | P3 | Used by `clientdbinfo` |
| `b_virtualserver_permission_find` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_custom_search` | Read | Not needed | — | ServerQuery only |
| `b_virtualserver_start` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_stop` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_token_list` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_token_add` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_token_use` | Connect | **Implicit** | P2 | Used in `clientinit` default_token |
| `b_virtualserver_token_delete` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_log_view` | Query | Not needed | — | ServerQuery only |
| `b_virtualserver_log_add` | Query | Not needed | — | ServerQuery only |
| `b_virtualserver_join_ignore_password` | Connect | Not needed | — | Rare |
| `b_virtualserver_notify_register` | Read | **Implicit** | P3 | Used by `servernotifyregister` |
| `b_virtualserver_notify_unregister` | Read | **Implicit** | P3 | Used by `servernotifyunregister` |
| `b_virtualserver_snapshot_create` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_snapshot_deploy` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_permission_reset` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_name` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_welcomemessage` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_maxclients` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_reserved_slots` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_password` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_default_servergroup` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_default_channelgroup` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_default_channeladmingroup` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_channel_forced_silence` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_complain` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_antiflood` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_ft_settings` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_ft_quotas` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_hostmessage` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_hostbanner` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_hostbutton` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_port` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_autostart` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_needed_identity_security_level` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_priority_speaker_dimm_modificator` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_log_settings` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_min_client_version` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_icon_id` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_weblist` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_codec_encryption_mode` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_temporary_passwords` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_temporary_passwords_own` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_channel_temp_delete_delay_default` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_nickname` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_modify_integrations` | Admin | Not needed | — | Admin operation |
### 3.3 Channel Permissions
| Permission Name | Category | Chanora Status | Priority | Notes |
|----------------|----------|----------------|----------|-------|
| `i_channel_min_depth` | Channel | Not needed | — | Server-side only |
| `i_channel_max_depth` | Channel | Not needed | — | Server-side only |
| `b_channel_group_inheritance_end` | Channel | Not needed | — | Server-side only |
| `i_channel_permission_modify_power` | Admin | Not needed | — | Admin operation |
| `i_channel_needed_permission_modify_power` | Admin | Not needed | — | Admin operation |
| `b_channel_info_view` | Read | **Implicit** | P3 | Used by `channelinfo` |
| `b_channel_create_child` | Channel | Not needed | — | Server-side only |
| `b_channel_create_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_create_semi_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_create_temporary` | Channel | Not needed | — | Server-side only |
| `b_channel_create_private` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_topic` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_description` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_password` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_speex8` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_speex16` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_speex32` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_celtmono48` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_opusvoice` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_codec_opusmusic` | Channel | Not needed | — | Server-side only |
| `i_channel_create_modify_with_codec_maxquality` | Channel | Not needed | — | Server-side only |
| `i_channel_create_modify_with_codec_latency_factor_min` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_maxclients` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_maxfamilyclients` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_sortorder` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_default` | Channel | Not needed | — | Server-side only |
| `b_channel_create_with_needed_talk_power` | Channel | Not needed | — | Server-side only |
| `b_channel_create_modify_with_force_password` | Channel | Not needed | — | Server-side only |
| `i_channel_create_modify_with_temp_delete_delay` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_parent` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_make_default` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_make_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_make_semi_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_make_temporary` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_name` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_topic` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_description` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_password` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_codec` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_codec_quality` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_codec_latency_factor` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_maxclients` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_maxfamilyclients` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_sortorder` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_needed_talk_power` | Channel | Not needed | — | Server-side only |
| `i_channel_modify_power` | Channel | Not needed | — | Server-side only |
| `i_channel_needed_modify_power` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_make_codec_encrypted` | Channel | Not needed | — | Server-side only |
| `b_channel_modify_temp_delete_delay` | Channel | Not needed | — | Server-side only |
| `b_channel_delete_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_delete_semi_permanent` | Channel | Not needed | — | Server-side only |
| `b_channel_delete_temporary` | Channel | Not needed | — | Server-side only |
| `b_channel_delete_flag_force` | Channel | Not needed | — | Server-side only |
| `i_channel_delete_power` | Channel | Not needed | — | Server-side only |
| `i_channel_needed_delete_power` | Channel | Not needed | — | Server-side only |
| `b_channel_join_permanent` | **Join** | **Implicit** | **P1** | Used by `clientmove` |
| `b_channel_join_semi_permanent` | **Join** | **Implicit** | **P1** | Used by `clientmove` |
| `b_channel_join_temporary` | **Join** | **Implicit** | **P1** | Used by `clientmove` |
| `b_channel_join_ignore_password` | **Join** | Not needed | P3 | Rare |
| `b_channel_join_ignore_maxclients` | **Join** | Not needed | P3 | Rare |
| `i_channel_join_power` | **Join** | **Implicit** | **P1** | Server evaluates on join |
| `i_channel_needed_join_power` | **Join** | **Implicit** | **P1** | Server evaluates on join |
| `i_channel_subscribe_power` | Subscribe | **Implicit** | P2 | Used by `channelsubscribe` |
| `i_channel_needed_subscribe_power` | Subscribe | **Implicit** | P2 | Used by `channelsubscribe` |
| `i_channel_description_view_power` | Read | Not needed | P3 | Low priority |
| `i_channel_needed_description_view_power` | Read | Not needed | P3 | Low priority |
### 3.4 Group Permissions
| Permission Name | Category | Chanora Status | Priority | Notes |
|----------------|----------|----------------|----------|-------|
| `i_icon_id` | Group | Not needed | — | Server-side only |
| `i_max_icon_filesize` | Group | Not needed | — | Server-side only |
| `b_icon_manage` | Group | Not needed | — | Server-side only |
| `b_group_is_permanent` | Group | Not needed | — | Server-side only |
| `i_group_auto_update_type` | Group | Not needed | — | Server-side only |
| `i_group_auto_update_max_value` | Group | Not needed | — | Server-side only |
| `i_group_sort_id` | Group | Not needed | — | Server-side only |
| `i_group_show_name_in_tree` | Group | Not needed | — | Server-side only |
| `b_virtualserver_servergroup_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_servergroup_permission_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_servergroup_client_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_channelgroup_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_channelgroup_permission_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_channelgroup_client_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_client_permission_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_channel_permission_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_channelclient_permission_list` | Group | Not needed | — | ServerQuery only |
| `b_virtualserver_servergroup_create` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_channelgroup_create` | Admin | Not needed | — | Admin operation |
| `i_group_modify_power` | Admin | Not needed | — | Admin operation |
| `i_group_needed_modify_power` | Admin | Not needed | — | Admin operation |
| `i_group_member_add_power` | Admin | Not needed | — | Admin operation |
| `i_group_needed_member_add_power` | Admin | Not needed | — | Admin operation |
| `i_group_member_remove_power` | Admin | Not needed | — | Admin operation |
| `i_group_needed_member_remove_power` | Admin | Not needed | — | Admin operation |
| `i_permission_modify_power` | Admin | Not needed | — | Admin operation |
| `b_permission_modify_power_ignore` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_servergroup_delete` | Admin | Not needed | — | Admin operation |
| `b_virtualserver_channelgroup_delete` | Admin | Not needed | — | Admin operation |
### 3.5 Client Permissions
| Permission Name | Category | Chanora Status | Priority | Notes |
|----------------|----------|----------------|----------|-------|
| `i_client_permission_modify_power` | Admin | Not needed | — | Admin operation |
| `i_client_needed_permission_modify_power` | Admin | Not needed | — | Admin operation |
| `i_client_max_clones_uid` | Connect | Not needed | — | Server-side only |
| `i_client_max_idletime` | Client | Not needed | P3 | Could display idle timeout |
| `i_client_max_avatar_filesize` | Client | Not needed | P3 | Could limit avatar upload |
| `i_client_max_channel_subscriptions` | Client | Not needed | P3 | Could limit subscriptions |
| `b_client_is_priority_speaker` | **Voice** | **Implicit** | **P1** | Tracked in `Client.is_priority_speaker` |
| `b_client_skip_channelgroup_permissions` | Client | Not needed | — | Server-side only |
| `b_client_force_push_to_talk` | **Voice** | Not needed | P2 | Could force PTT mode |
| `b_client_ignore_bans` | Client | Not needed | — | Server-side only |
| `b_client_ignore_antiflood` | Client | Not needed | — | Server-side only |
| `b_client_issue_client_query_command` | Query | Not needed | — | ServerQuery only |
| `b_client_use_reserved_slot` | Connect | Not needed | P3 | Could show slot availability |
| `b_client_use_channel_commander` | **Voice** | Not needed | P2 | Channel commander feature |
| `b_client_request_talker` | **Voice** | **Implicit** | **P1** | `client_talk_request` in events |
| `b_client_avatar_delete_other` | Client | Not needed | — | Server-side only |
| `b_client_is_sticky` | Client | Not needed | P3 | Could show sticky indicator |
| `b_client_ignore_sticky` | Client | Not needed | P3 | Could show sticky indicator |
| `b_client_info_view` | **Read** | **Implicit** | **P1** | Used by `clientinfo` |
| `b_client_permissionoverview_view` | Read | Not needed | — | ServerQuery only |
| `b_client_permissionoverview_own` | Read | Not needed | — | ServerQuery only |
| `b_client_remoteaddress_view` | **Read** | **Implicit** | **P2** | Gated in `BridgeClientProfile.client_address` |
| `i_client_serverquery_view_power` | Read | Not needed | P3 | Could gate query client visibility |
| `i_client_needed_serverquery_view_power` | Read | Not needed | P3 | Could gate query client visibility |
| `b_client_custom_info_view` | Read | Not needed | P3 | Custom fields |
| `i_client_kick_from_server_power` | **Moderation** | Not needed | **P1** | Future: kick UI |
| `i_client_needed_kick_from_server_power` | **Moderation** | Not needed | **P1** | Future: kick UI |
| `i_client_kick_from_channel_power` | **Moderation** | Not needed | **P1** | Future: kick UI |
| `i_client_needed_kick_from_channel_power` | **Moderation** | Not needed | **P1** | Future: kick UI |
| `i_client_ban_power` | **Moderation** | Not needed | **P1** | Future: ban UI |
| `i_client_needed_ban_power` | **Moderation** | Not needed | **P1** | Future: ban UI |
| `i_client_move_power` | **Moderation** | Not needed | **P1** | Future: move UI |
| `i_client_needed_move_power` | **Moderation** | Not needed | **P1** | Future: move UI |
| `i_client_complain_power` | Moderation | Not needed | P2 | Future: complain UI |
| `i_client_needed_complain_power` | Moderation | Not needed | P2 | Future: complain UI |
| `b_client_complain_list` | Moderation | Not needed | P2 | Future: complain UI |
| `b_client_complain_delete_own` | Moderation | Not needed | P2 | Future: complain UI |
| `b_client_complain_delete` | Moderation | Not needed | P2 | Future: complain UI |
| `b_client_ban_list` | Moderation | Not needed | P2 | Future: ban UI |
| `b_client_ban_create` | Moderation | Not needed | P2 | Future: ban UI |
| `b_client_ban_delete_own` | Moderation | Not needed | P2 | Future: ban UI |
| `b_client_ban_delete` | Moderation | Not needed | P2 | Future: ban UI |
| `i_client_ban_max_bantime` | Moderation | Not needed | P2 | Future: ban UI |
| `i_client_private_textmessage_power` | **Chat** | Not needed | **P1** | Could gate DM UI |
| `i_client_needed_private_textmessage_power` | **Chat** | Not needed | **P1** | Could gate DM UI |
| `b_client_server_textmessage_send` | **Chat** | Not needed | **P1** | Could gate server chat |
| `b_client_channel_textmessage_send` | **Chat** | Not needed | **P1** | Could gate channel chat |
| `b_client_offline_textmessage_send` | Chat | Not needed | P2 | Offline messages |
| `i_client_talk_power` | **Voice** | **Implicit** | **P1** | Tracked in `Client.talk_power` |
| `i_client_needed_talk_power` | **Voice** | **Implicit** | **P1** | Compared against channel `needed_talk_power` |
| `i_client_poke_power` | Chat | Not needed | P2 | Could gate poke UI |
| `i_client_needed_poke_power` | Chat | Not needed | P2 | Could gate poke UI |
| `b_client_set_flag_talker` | **Voice** | Not needed | **P1** | Future: grant talk power |
| `i_client_whisper_power` | **Voice** | Not needed | P2 | Whisper feature |
| `i_client_needed_whisper_power` | **Voice** | Not needed | P2 | Whisper feature |
| `b_client_modify_description` | Client | Not needed | P2 | Future: edit description |
| `b_client_modify_own_description` | Client | Not needed | P2 | Future: edit own description |
| `b_client_modify_dbproperties` | Client | Not needed | — | Server-side only |
| `b_client_delete_dbproperties` | Client | Not needed | — | Server-side only |
| `b_client_create_modify_serverquery_login` | Query | Not needed | — | ServerQuery only |
### 3.6 File Transfer Permissions
| Permission Name | Category | Chanora Status | Priority | Notes |
|----------------|----------|----------------|----------|-------|
| `b_ft_ignore_password` | File | Not needed | P3 | File browser |
| `b_ft_transfer_list` | File | Not needed | P3 | File browser |
| `i_ft_file_upload_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_file_upload_power` | File | Not needed | P3 | File browser |
| `i_ft_file_download_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_file_download_power` | File | Not needed | P3 | File browser |
| `i_ft_file_delete_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_file_delete_power` | File | Not needed | P3 | File browser |
| `i_ft_file_rename_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_file_rename_power` | File | Not needed | P3 | File browser |
| `i_ft_file_browse_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_file_browse_power` | File | Not needed | P3 | File browser |
| `i_ft_directory_create_power` | File | Not needed | P3 | File browser |
| `i_ft_needed_directory_create_power` | File | Not needed | P3 | File browser |
| `i_ft_quota_mb_download_per_client` | File | Not needed | P3 | File browser |
| `i_ft_quota_mb_upload_per_client` | File | Not needed | P3 | File browser |
---
## 4. Summary: Permissions Chanora Should Track
### 4.1 Already Handled (Implicit via Protocol)
These permissions are evaluated server-side; Chanora sends commands and handles rejection:
| Permission | How Handled |
|-----------|-------------|
| `b_channel_join_*` | `voice_join` → server rejects with error code |
| `i_channel_join_power` / `i_channel_needed_join_power` | Server evaluates; Chanora gets `JoinDenied` |
| `b_client_info_view` | `clientinfo` command; server returns error if denied |
| `b_client_remoteaddress_view` | `client_address` field gated in `BridgeClientProfile` |
| `i_client_talk_power` / `i_client_needed_talk_power` | Tracked in `Client.talk_power`; server enforces |
| `b_client_is_priority_speaker` | Tracked in client state |
| `b_client_request_talker` | Tracked via `client_talk_request` events |
### 4.2 Missing — Should Add (P1)
| Permission | Reason | Implementation |
|-----------|--------|----------------|
| `i_client_kick_from_server_power` / `i_client_kick_from_channel_power` | Future kick UI needs to know if user can kick | Add to `BridgeClientProfile` or `PermissionHints` |
| `i_client_ban_power` | Future ban UI | Add to permission hints |
| `i_client_move_power` | Future move UI | Add to permission hints |
| `i_client_private_textmessage_power` | Gate DM input in UI | Add to permission hints |
| `b_client_server_textmessage_send` | Gate server chat input | Add to permission hints |
| `b_client_channel_textmessage_send` | Gate channel chat input | Add to permission hints |
| `b_client_set_flag_talker` | Future "grant talk power" button | Add to permission hints |
### 4.3 Missing — Nice to Have (P2-P3)
| Permission | Reason |
|-----------|--------|
| `b_client_force_push_to_talk` | Could force PTT mode in UI |
| `b_client_use_channel_commander` | Channel commander feature |
| `i_client_whisper_power` | Whisper feature |
| `b_client_complain_*` | Complain UI |
| `b_client_ban_*` | Ban management UI |
| `i_ft_*` | File transfer browser permissions |
---
## 5. Recommended Implementation
### 5.1 Permission Constants Module
Generate from `Permissions.csv`:
```rust
// crates/chanora_protocol/src/permissions.rs
// Auto-generated from ReSpeak/tsdeclarations Permissions.csv
pub const B_CHANNEL_JOIN_PERMANENT: &str = "b_channel_join_permanent";
pub const B_CHANNEL_JOIN_SEMI_PERMANENT: &str = "b_channel_join_semi_permanent";
pub const B_CHANNEL_JOIN_TEMPORARY: &str = "b_channel_join_temporary";
pub const I_CHANNEL_JOIN_POWER: &str = "i_channel_join_power";
pub const I_CHANNEL_NEEDED_JOIN_POWER: &str = "i_channel_needed_join_power";
// ... all 253 permissions
```
### 5.2 Permission Hints Integration
Extend the existing `PermissionHints` bitflags (already in `Enums.toml` / ReSpeak §6) to cover the P1 permissions. The server already sends `PermissionHints` in `clientinfo` responses — Chanora just needs to parse and expose them.
### 5.3 UI Gating
Add permission-aware UI state to `BridgeEvent` or `BridgeClientProfile`:
```rust
pub struct BridgePermissionHints {
pub can_kick_server: bool,
pub can_kick_channel: bool,
pub can_ban: bool,
pub can_move: bool,
pub can_send_private_message: bool,
pub can_send_server_message: bool,
pub can_send_channel_message: bool,
pub can_grant_talk_power: bool,
}
```
---
*Created: 2026-06-11 for TODO-069*
@@ -0,0 +1,143 @@
# tsdeclarations Code Generation Evaluation
**TODO-068** — Evaluate Messages.toml, Book.toml, Enums.toml for code generation feasibility.
---
## 1. What tsdeclarations Provides
The [ReSpeak/tsdeclarations](https://github.com/ReSpeak/tsdeclarations) repository contains machine-readable protocol data files used for code generation across the ReSpeak ecosystem:
| File | Purpose | Format |
|------|---------|--------|
| `Messages.toml` | All TS3 client↔server commands and their parameters | TOML structs with typed fields |
| `Book.toml` | State-tracking structures for server entities (Client, Channel, Server, ServerGroup, etc.) | TOML structs with typed fields |
| `Enums.toml` | Protocol enums (Codec, PermissionType, Reason, ChannelType, LicenseType, etc.) | TOML enum definitions |
| `MessagesToBook.toml` | Mappings from incoming commands to Book struct updates | TOML mapping rules |
| `BookToMessages.toml` | Functions to generate outgoing commands from Book state | TOML generation rules |
| `Errors.csv` | All TS3 error codes (hex, name, description) | CSV |
| `Permissions.csv` | All TS3 permission IDs (name, description, numeric ID) | CSV |
| `Versions.csv` | Known client version hashes (1536 entries) | CSV |
| `Badges.csv` | Known badge GUIDs and metadata | CSV |
### How ReSpeak Uses Them
The `tsclientlib` workspace consumes these via:
- **`tsproto-structs`** — build-time code generation from TOML files into Rust structs
- **`tsproto-types`** — basic TS3 types (error codes, versions, UIDs)
- **`ts-bookkeeping`** — state tracking that maps incoming messages to Book struct updates
- **`tsproto-packets`** — command parsing/serialization
Chanora already depends on `tsproto-structs`, `tsproto-types`, and `ts-bookkeeping` as git dependencies (via `chanora_protocol`).
---
## 2. Current Chanora Usage
| Component | Source | Status |
|-----------|--------|--------|
| `tsproto-types` | Git dependency (patched fork for P-256 coordinate padding) | Active |
| `tsproto-structs` | Git dependency (rev 04aa2491) | Active |
| `ts_bookkeeping` | Used in `chanora_protocol/src/adapter.rs` for event projection | Active |
| Error codes | Referenced from `Errors.csv` via `tsproto-types` | Active |
| Version hashes | Baked into `adapter.rs` from `Versions.csv` | Active |
| Permissions | **Not used** — no TS3 permission ID mapping exists in Chanora |
| `Messages.toml` | **Not directly used** — Chanora uses `ts_bookkeeping` which consumes it internally |
| `Book.toml` | **Not directly used** — consumed by `ts_bookkeeping` internally |
| `Enums.toml` | **Not directly used** — consumed by `tsproto-structs` internally |
---
## 3. Feasibility Assessment
### 3.1 Automating Protocol Struct Generation
**Verdict: Already happening indirectly via tsproto-structs/ts_bookkeeping.**
Chanora already benefits from the tsdeclarations code generation pipeline through its dependency on `tsproto-structs` and `ts_bookkeeping`. The TOML files are consumed at build time by these upstream crates, producing:
- Typed command structs (`c2s::Clientinit`, `s2c::Initserver`, etc.)
- Event mapping logic (`Event`, `PropertyId`, `PropertyValue`)
- Book state structures
Direct consumption of `Messages.toml`/`Book.toml` to generate *Chanora-specific* structs would be **redundant** with the existing `ts_bookkeeping` dependency.
### 3.2 Generating Chanora-Specific DTOs from Book.toml
**Verdict: Moderate value, moderate effort.**
The `Book.toml` defines the canonical shape of tracked entities (Client, Channel, Server, ServerGroup, ChannelGroup). Chanora currently has its own DTO types:
- `BridgeClient` / `BridgeChannel` / `BridgeSnapshot` (in `chanora_bridge/src/api.rs`)
- `ClientProfile` / `ServerSnapshot` (in `chanora_core`)
A code-gen step could auto-generate these DTOs from `Book.toml`, ensuring field parity with the protocol. However:
- Chanora's DTOs intentionally omit many protocol fields (privacy, simplicity)
- The mapping from Book fields to bridge DTOs involves business logic (e.g., `PermissionHints` gating)
- Manual DTOs are easier to evolve independently
**Recommendation:** Keep manual DTOs. Use `Book.toml` as a *reference* when adding new fields, not as a code-gen source.
### 3.3 Generating Event Types from Messages.toml
**Verdict: Low value for Chanora.**
`ts_bookkeeping` already handles the command→event mapping. Chanora's `SessionEvent` enum is a higher-level abstraction that doesn't map 1:1 to protocol commands. Auto-generating it from `Messages.toml` would require a complex mapping layer that defeats the purpose.
### 3.4 Error Code and Permission ID Generation
**Verdict: High value, low effort.**
The CSV files (`Errors.csv`, `Permissions.csv`) are simple, stable, and directly useful:
- **Errors**: Chanora already references `Errors.csv` names but hardcodes hex values. A build step could generate a `const` table.
- **Permissions**: No permission ID mapping exists yet (TODO-069). `Permissions.csv` is the canonical source.
### 3.5 Version Hash Generation
**Verdict: Already done manually; automation possible but low priority.**
Version hashes from `Versions.csv` are baked into `adapter.rs` at vendor time. A build step could auto-update them, but the list changes infrequently.
---
## 4. Recommended Approach
| Priority | Action | Effort | Value |
|----------|--------|--------|-------|
| P1 | Use `Permissions.csv` to generate a Rust permission ID constants module (see TODO-069) | 12 days | High |
| P2 | Use `Errors.csv` to generate a typed error code enum with `From<u16>` | 0.5 days | Medium |
| P3 | Add a CI check that diffs `tsproto-structs`/`ts_bookkeeping` against upstream tsdeclarations HEAD | 0.5 days | Medium |
| P4 | Keep `Book.toml`/`Messages.toml` as reference documentation only | 0 days | — |
### What NOT to Do
- **Do not** fork or vendor the TOML files into Chanora's build pipeline
- **Do not** auto-generate Chanora's bridge DTOs from `Book.toml`
- **Do not** auto-generate `SessionEvent` from `Messages.toml`
- **Do not** maintain a separate TOML parser — let upstream crates handle this
---
## 5. Effort Estimate
| Task | Estimate |
|------|----------|
| Permission ID constants from `Permissions.csv` | 12 days |
| Error code enum from `Errors.csv` | 0.5 days |
| CI upstream diff check | 0.5 days |
| **Total** | **23 days** |
---
## 6. Dependencies and Risks
- **Upstream stability**: `tsdeclarations` is MIT/Apache-2.0 licensed, active (94 commits), and used by `tsclientlib`. Low risk of abandonment.
- **TS5 compatibility**: The files may need updates when TS5 protocol stabilizes (TODO-058 monitors this).
- **Patched fork**: Chanora uses a patched `tsproto-types` fork for P-256 coordinate padding. Any code-gen from upstream must account for this.
---
*Created: 2026-06-11 for TODO-068*